在Parallel.Foreach中分块IEnumerable

时间:2013-05-07 19:41:58

标签: c# .net multithreading parallel-processing

有没有人知道让Parallel.Foreach循环使用块分区的方法,我认为默认情况下是范围分区。使用数组时似乎很简单,因为您只需创建自定义分区程序并将负载均衡设置为true即可。

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

任何帮助都将不胜感激。

谢谢!

我尝试在每个对象上执行的任务执行的时间明显不同。最后,我通常会等待最后一个线程完成其工作的时间。我想要实现的是在整个过程中使用并行循环请求块,而不是预先为每个线程分配项目。

2 个答案:

答案 0 :(得分:21)

如果你的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答案中涵盖,但您可以查看this guide on the MSDN以帮助您入门。

更新:从.NET 4.5开始,他们添加了一个不缓冲数据的Partitioner.Create重载,它与制作范围最大为1的自定义分区具有相同的效果。有了这个,你就不会得到一个排队排队的单个线程,如果它连续运行了很多慢的项目就不行了。

var partitoner = Partitioner.Create(source, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitoner, item =>
{
    //Do work
}

答案 1 :(得分:2)

MSDN Samples for Parallel Programming with the .NET Framework包含ChunkPartitioner的实现。它包含在ParallelExtensionsExtra项目中。