我有一个并行的Foreach循环,它循环遍历一个项目列表,并对它们执行一些操作。根据项目的不同,其中一些操作比其他操作需要更长的时间。
Parallel.ForEach(list, new ParallelOptions { MaxDegreeOfParallelism = 5 }, item =>
{
var subItems = item.subItems;
foreach (var subItem in subItems)
{
//do some actions for subItem
}
Console.WriteLine("Action Complete for {0}", item);
});过了一段时间,当列表中只剩下5-10个要运行的项目时,似乎只剩下一个线程在运行。这并不理想,因为一些项目会被卡在另一个项目后面才能完成。
如果我停止脚本,然后重新启动它,列表中只剩下5-10个项目,它会启动多个线程,再次并行执行每个项目。
我如何才能确保其他线程继续被使用,而不需要重新启动脚本?
发布于 2014-04-12 01:31:48
这里的问题是,默认的分区程序将每个任务的工作阻塞为N个items块。它假设项目的数量很大,并且每个项目都需要相同的时间,那么您可以预期,几个线程将运行最后的~N*5个项目,并同时完成所有项目。
然而,在您的情况下,情况并非如此。您可以编写自己的Partitioner,以便在每个块中使用较少的项,请参阅Partitioner Class。这可能会提高性能,但如果每个项目完成的工作量非常小,那么您将增加管理任务的有用工作量与已完成工作量的比率,并可能降低性能。
您还可以编写一个动态分区程序来减小分区大小,以便最后几个项目位于较小的分区中,从而确保您仍在使用所有可用的线程。这篇MSDN文章介绍了如何编写自定义分区程序Custom Partitioners for PLINQ and TPL。
https://stackoverflow.com/questions/23015419
复制相似问题