C# 用Parallel.foreach替换顺序foreach
在下面的C# 用Parallel.foreach替换顺序foreach,c#,parallel-processing,C#,Parallel Processing,在下面的foreach p:allPersons中,很明显(因为逻辑是顺序的),map/Dictionary可以用于缓存/记忆 Dictionary<string, int> personNameToIdMap = new Dictionary<string, int>(); foreach(p : allPersons) { int outputId; if(personNameToIdMap.TryGetValue(p.Name, out outputId)
foreach p:allPersons
中,很明显(因为逻辑是顺序的),map/Dictionary可以用于缓存/记忆
Dictionary<string, int> personNameToIdMap = new Dictionary<string, int>();
foreach(p : allPersons)
{
int outputId;
if(personNameToIdMap.TryGetValue(p.Name, out outputId))
{
// nothing to do since map contained the p.Name
}
else
{
outputId = doExpensiveLookup(p.Name);
personNameToIdMap[p.Name] = outputId;
}
...
p.Id = outputId;
}
Dictionary personNameToIdMap=new Dictionary();
foreach(p:所有人)
{
int输出;
if(personnametodmap.TryGetValue(p.Name,out outputId))
{
//由于地图包含p.名称,因此无需执行任何操作
}
其他的
{
outputId=doExpensiveLookup(p.Name);
personNameToIdMap[p.Name]=输出;
}
...
p、 Id=输出;
}
如果我将上面的
foreach
替换为Parallel.foreach
,每个线程是否会共享personNameToIdMap
?是,如果是并行。foreach
每个线程将使用相同的字典实例
如果你真的想要并行,你可以使用线程安全版本的字典是的,在并行的情况下。Foreach
每个线程将使用相同的字典实例
如果您真的想要并行性,您可以使用线程安全版本的字典是完全正确的-ConcurrentDictionary
将是正确的方法。有鉴于此,您可能希望稍微更改您的方法,以利用ConcurrentDictionary
的方法:
ConcurrentDictionary personNameToIdMap=新建ConcurrentDictionary();
Parallel.ForEach(所有人,p=>
{
int outputId=personNameToIdMap.GetOrAdd(p.Name,Name=>doExpensiveLookup(p.Name));
// ...
p、 Id=输出;
}
是完全正确的-ConcurrentDictionary
将是正确的方法。鉴于此,您可能需要稍微更改您的方法以利用ConcurrentDictionary
的方法:
ConcurrentDictionary personNameToIdMap=新建ConcurrentDictionary();
Parallel.ForEach(所有人,p=>
{
int outputId=personNameToIdMap.GetOrAdd(p.Name,Name=>doExpensiveLookup(p.Name));
// ...
p、 Id=输出;
}
请注意,您展示的foreach语法不是C#)这里是C#和C++11语法的有趣混合…里德-我最近在Java中工作了相当长的时间,所以我的C#语法不是100%-请注意,您展示的foreach语法不是C#)C#和C++11语法的有趣组合在这里…里德-我最近在Java中工作了相当长的时间,所以我的C#语法不是100%-ha+1 ConcurrentDictionary肯定是最好的选择,但如果稍微改变一下逻辑可能会更好。+1。使用并发字典,您是否希望在并行中会有很多争用。ForEach
线程最终会在哪里相互争斗?@Moo Juice显然会有一些开销,因为有多个线程,这就是为什么我编写了如果您真的想要并行
:)@Moo Juice在这种情况下,争用应该非常低,因为读取非常便宜,几乎没有写入/添加(在这段代码中),并且CD执行非常细粒度的锁定。@Kevin比这更糟糕-字典
不是线程安全的,因此如果在没有锁定/同步的情况下从多个线程使用它,则会出现未定义的行为。基本上,你真的不知道你会得到什么-这可能是正确的答案,多个线程可能都试图相互写入,你可能会在设置之前尝试访问一些内部结构时遇到崩溃,等等…+1 ConcurrentDictionary肯定是一条路要走,但如果稍微改变一下逻辑可能会是最好的。+1。使用并发字典,您是否希望在并行中会有很多争用。ForEach
线程最终会在哪里相互争斗?@Moo Juice显然会有一些开销,因为有多个线程,这就是为什么我编写了如果您真的想要并行
:)@Moo Juice在这种情况下,争用应该非常低,因为读取非常便宜,几乎没有写入/添加(在这段代码中),并且CD执行非常细粒度的锁定。@Kevin比这更糟糕-字典
不是线程安全的,因此如果在没有锁定/同步的情况下从多个线程使用它,则会出现未定义的行为。基本上,你真的不知道你会得到什么-这可能是正确的答案,多个线程可能都试图相互写入,你可能会在设置之前尝试访问某些内部结构时遇到崩溃,等等…是否有必要确保所有人
都是线程安全的?目前它是一个列表
,但我在C#List文档中读到列表
不是线程-safe@Kevin否-IEnumerable
本质上不是线程安全的-因此,Parallel
将为您处理该部分。使用列表
可以。是否有必要确保所有人
都是线程安全的?目前它是一个列表
,但我在C#List文档中读到列表
不是线程-safe@Kevin否-IEnumerable
本质上不是线程安全的-因此,Parallel
将为您处理该部分。在那里使用列表
很好。
ConcurrentDictionary<string, int> personNameToIdMap = new ConcurrentDictionary<string, int>();
Parallel.ForEach(allPersons, p =>
{
int outputId = personNameToIdMap.GetOrAdd(p.Name, name => doExpensiveLookup(p.Name));
// ...
p.Id = outputId;
}