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;
}