11

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

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<int> CreateItems(int count)
    {
        for (int i = 0; i < count; i++)
        {
            yield return i;
        }
    }

    private static void ProcessItem(int item)
    {
        // Do something
    }
}

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

4

2 回答 2

12

Parallel.ForEach<TSource>, when TSourceis an IEnumerable<T>, 创建一个分区器IEnumerable<T>包括它自己的内部锁定机制,所以你不需要在你的迭代器中实现任何线程安全。

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

  1. 获取共享锁
  2. 遍历源(从它离开的地方)以检索项目块,将项目保存在私有数组中
  3. 释放锁,以便可以满足其他块请求。
  4. 从其私有数组中为工作线程提供服务。

如您所见,IEnumerable<T>出于分区目的的运行是顺序的(通过共享锁访问),并且分区是并行处理的。

于 2013-06-10T12:21:46.003 回答
2

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

Partitioner 是一种类型,它继承Partitioner<TSource>并用于将源序列拆分为多个部分(或分区)。内置分区器旨在将源序列拆分为不重叠的分区。

于 2013-06-10T10:49:56.977 回答