这是在多线程方法中安全使用 Dictionary 吗?

Is this a safe use of Dictionary in a multi-threaded method?

我有一个使用 Parallel.ForEach 迭代的项目集合 (SortedPoints)。每个项目都将成为名为 Stripes 的字典中的键。计算每个项目的价值是昂贵的,并且在方法 BulidStripes 中。

Parallel.ForEach(SortedPoints, point =>
    Stripes[point] = BuildStripes(point, pointToPosition)
); 

我可以将 Stripes 设为 ConcurrentDictionary,但我想知道这是否可行:

1) 使 Stripes 成为常规词典。

2) 连续遍历所有点并用到空对象的映射填充条纹。

3) 并行遍历所有点,将 Stripes 中的映射替换为 BuildStripes 返回的实际值。

foreach(var point in SortedPoints)
    Stripes[point] = emptyStripe;
Parallel.ForEach(SortedPoints, point =>
    Stripes[point] = BuildStripes(point, pointToPosition)
);

如果每个线程都在一组单独的键上工作并且每个键都按我概述的顺序预加载到字典中,那么设置键的值是否是线程安全的?我查看了 Dictionary 的源代码,它看起来很安全,但这些集合是微妙的野兽,很难发现并行错误。

字典一旦创建,我再也不会修改它,所有访问都是读取。

让我们看看事实。如果出现以下情况,可能会发生线程错误:

  • 添加新项目?没有
  • 添加项目时调整词典大小。这不是问题,你的字典有固定大小。
  • 两个线程尝试设置同一个键的值。不会发生,因为您的 SortedPoints 集合有不同的项目(是吗?)

还有其他选择吗?我没有看到一个。我认为你可以安全地使用这种方法。

当然,为了可读性,只需使用常规的 ConcurrentDictionnary!也许您可以获得一些性能,但除非您对其进行基准测试,否则没有理由不使用 ConcurrentDictionary。

Some docs about what ConcurrentDictionary deal with.