返回tolist()的plinq是否是线程安全的? [英] Is the plinq that returning the tolist() is thread safe?
本文介绍了返回tolist()的plinq是否是线程安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
在下面的代码中,UE是字典,bg是列表。
我使用PLINQ从字典中获取值并返回列表。
是以下代码是线程安全的吗?
TIA
我尝试了什么:
t = UE.AsParallel()。Where(x => bg.Contains(x.Key,StringComparer.OrdinalIgnoreCase))。选择(y => ; y.Value).Distinct()。ToList();
In the below below code UE is dictionary and bg is the list.
I am using PLINQ to get the values from the dictionary and returning the list.
Is the below code is thread safe?
TIA
What I have tried:
t = UE.AsParallel().Where(x => bg.Contains(x.Key, StringComparer.OrdinalIgnoreCase)).Select(y => y.Value).Distinct().ToList();
推荐答案
只要您只是阅读而不修改值,任何东西都是线程安全的。
As long as you're only reading and not modifying values anything is thread safe.
Sascha关于线程安全是正确的。
但是,如果你使用.AsParallel()
来改进性能,你错了!
由于bg
是一个List< ; string>
,.Contains()
是一种检查列表成员资格的非常糟糕的方法。它是 O(n)(其中 n 是bg.Length
)。因此整体查询 O(n * m)(其中 mUE.Count
)。
相反,您应该从bg
创建一个HashSet< string>
并检查该集合中的成员资格。 O(1),使整体查询与UE.Count
成正比。
使用HashSet
比的(在我的系统上)<并行扫描bg
。
并行化HashSet版本实际上减慢了它的速度,可能是由于并行化设置和上下文切换以及协调开销。
这是我的测试代码:
Sascha is correct about thread safety.
However, if you are using the.AsParallel()
to improve performance, you're going about it incorrectly!
Sincebg
is aList<string>
, the.Contains()
is a very poor way to check for membership in the list. It is O(n) (where n isbg.Length
). So the overall query is O(n*m) (where m isUE.Count
).
Instead, you should make aHashSet<string>
frombg
and check for membership in the set. That is O(1), making the overall query directly proportional toUE.Count
.
Using theHashSet
is about 100 times faster (on my system) than the parallelized scan ofbg
.
Parallelizing the HashSet version actually slows it down, presumably due to the parallelization setup and context switching and coordination overhead.
Here's my testing code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
Stopwatch swp = new Stopwatch();
Stopwatch swh = new Stopwatch();
Stopwatch swph = new Stopwatch();
bool tail = false;
const int count = 200;
for (int i = 0; i <= count; i++)
{
// Populate the collections
Dictionary<string, int> UE = new Dictionary<string, int>();
List<string> bg = new List<string>();
int roff = rand.Next(1000);
foreach (var item in Enumerable.Range(roff, 10000))
{
string key = item.ToString("D");
UE.Add(key, item % (roff + 500));
if (item % 10 == 0)
bg.Add(key);
}
// skip timing the first time through so we're sure the JITTER isn't included.
if (tail)
swp.Start();
List<int> tp = UE.AsParallel().Where(x => bg.Contains(x.Key, StringComparer.OrdinalIgnoreCase)).Select(y => y.Value).Distinct().ToList();
if (tail)
swp.Stop();
if (tail)
swh.Start();
HashSet<string> hs = new HashSet<string>(bg, StringComparer.OrdinalIgnoreCase);
List<int> th = UE.Where(x => hs.Contains(x.Key)).Select(y => y.Value).Distinct().ToList();
if (tail)
swh.Stop();
if (tail)
swph.Start();
HashSet<string> hps = new HashSet<string>(bg, StringComparer.OrdinalIgnoreCase);
List<int> tph = UE.AsParallel().Where(x => hps.Contains(x.Key)).Select(y => y.Value).Distinct().ToList();
if (tail)
swph.Stop();
tail = true;
// so GC of per-timing-iteration garbage isn't included in timing
UE = null;
bg = null;
hs = null;
hps = null;
GC.Collect();
}
Console.WriteLine("Parallel processing: {0:F2} ticks (avg)", swp.ElapsedTicks / (double)count);
Console.WriteLine("HashSet processing: {0:F2} ticks (avg)", swh.ElapsedTicks / (double)count);
Console.WriteLine("Parallel & HashSet processing: {0:F2} ticks (avg)", swph.ElapsedTicks / (double)count);
Console.WriteLine("Return to exit");
Console.ReadLine();
}
}
}
这篇关于返回tolist()的plinq是否是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文