有没有人知道让Parallel.Foreach循环使用块分区的方法,我认为默认情况下是范围分区。使用数组时似乎很简单,因为您只需创建自定义分区程序并将负载均衡设置为true即可。
由于IEnumerable中的元素数量直到运行时才知道,我似乎无法找到一种让块分区工作的好方法。
任何帮助都将不胜感激。
谢谢!
我尝试在每个对象上执行的任务执行的时间明显不同。最后,我通常会等待最后一个线程完成其工作的时间。我想要实现的是在整个过程中使用并行循环请求块,而不是预先为每个线程分配项目。
答案 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
项目中。