随着Parallel.Foreach循环继续,线程数减少

时间:2014-04-11 14:27:39

标签: multithreading foreach parallel-processing

我有一个Parallel 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个项目要运行时,似乎只有1个线程在运行。这并不理想,因为有些物品会被卡在另一个物品后面完成。

如果我停止脚本,然后再次启动它,只有列表中剩余的5-10个项目,它会旋转多个线程再次并行执行每个项目。

如何在不需要重新启动脚本的情况下确保其他线程继续使用?

1 个答案:

答案 0 :(得分:2)

这里的问题是默认分区程序将每个任务的工作阻塞到N items的块中。它假定项目数量很大,每个项目花费的时间与您预期的几个线程将运行最后的~N * 5项目并且所有项目同时完成相同。

然而在你的情况下,这不是真的。您可以编写自己的Partitioner,以便每个块使用较少数量的项目,请参阅Partitioner Class。这可能会提高性能,但每个项目完成的工作量非常小,那么您将增加有用工作与完成任务的工作比例,并可能降低性能。

您还可以编写一个动态分区程序来减少分区大小,以便最后几个项目位于较小的分区中,从而确保您仍在使用所有可用的线程。此MSDN文章介绍了编写自定义分区程序Custom Partitioners for PLINQ and TPL