使用Parallel.ForEach()获得yield返回的线程安全性

请考虑以下代码示例,该示例创建可枚举的整数集合并并行处理它:

using System.Collections.Generic; using System.Threading.Tasks; public class Program { public static void Main() { Parallel.ForEach(CreateItems(100), item => ProcessItem(item)); } private static IEnumerable CreateItems(int count) { for (int i = 0; i < count; i++) { yield return i; } } private static void ProcessItem(int item) { // Do something } } 

是否保证Parallel.ForEach()生成的工作线程每个都获得一个不同的项目,或者是一些围绕增量和返回所需的锁定机制?

Parallel.ForEach ,当TSourceIEnumerable ,为IEnumerable创建一个包含其自己的内部锁定机制的分区器,因此您不需要在迭代器中实现任何线程安全性。

每当工作线程请求一大块项目时,分区器将创建一个内部枚举器 ,其中:

  1. 获取共享锁
  2. 迭代源(从它离开的位置)来检索项目块,将项目保存在私有数组中
  3. 释放锁定,以便可以实现其他块请求。
  4. 从其私有数组中提供工作线程。

如您所见,为了分区而运行IEnumerable是顺序的(通过共享锁访问),并且并行处理分区。

TPL和PLINQ使用分区器的概念。

分区程序是一种类型,它inheritancePartitioner并用于将源序列拆分为多个部分(或分区)。 内置分区器旨在将源序列拆分为非重叠分区。