23

有谁知道让 Parallel.Foreach 循环使用块分区的方法,而我认为默认情况下是范围分区。使用数组时看起来很简单,因为您只需创建一个自定义分区器并将负载平衡设置为 true。

由于 IEnumerable 中的元素数量直到运行时才知道,我似乎无法找到让块分区工作的好方法。

任何帮助,将不胜感激。

谢谢!

我试图在每个对象上执行的任务需要花费显着不同的时间来执行。最后,我通常要等待几个小时才能完成最后一个线程的工作。我想要实现的是沿途有并行循环请求块,而不是为每个线程预先分配项目。

4

1 回答 1

29

如果您的 IEnumerable 确实具有索引器(即您可以obj[1]将项目取出),您可以执行以下操作

    var rangePartitioner = Partitioner.Create(0, source.Length);
    Parallel.ForEach(rangePartitioner, (range, loopState) =>
    {
        // Loop over each range element without a delegate invocation. 
        for (int i = range.Item1; i < range.Item2; i++)
        {
            var item = source[i]
            //Do work on item
        }
    });

但是,如果它不能这样做,您必须通过创建一个派生自System.Collections.Concurrent.Partitioner<TSource>. 该主题过于广泛,无法在 SO 答案中涵盖,但您可以查看MSDN 上的本指南以帮助您入门。

更新:从 .NET 4.5 开始,他们添加了一个Partitioner.Create不缓冲数据的重载,它与创建一个范围最大大小为 1 的自定义分区器具有相同的效果。这样你就不会得到一个拥有一堆如果连续一堆慢项目不走运,则排队工作。

var partitoner = Partitioner.Create(source, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitoner, item =>
{
    //Do work
}
于 2013-05-07T19:53:08.667 回答