使用多个有限数量的线程处理项目列表

时间:2011-03-02 22:04:02

标签: c# .net multithreading plinq parallel-extensions

基本上,我想要处理多个线程中的项目列表,而不是一次处理一个。 我一次只想要有限数量的线程。 这种方法有意义吗?使用全局变量进行线程计数是唯一的选择吗? (下面的伪代码)

foreach item in list
    while thread_count >= thread_max
        sleep
    loop
    start_thread item
    thread_count++
next

function start_thread(item)
    do_something_to item
    thread_count--
end function

2 个答案:

答案 0 :(得分:6)

我会使用PLINQ并指定最大并行度,如下所示:

我实际上是在改变我的答案,因为我意识到你只想直接处理原始列表而你没有做任何其他过滤或映射(Where / Select)。在这种特殊情况下,最好使用Parallel :: ForEach并通过ParallelOptions指定MaxDegreeOfParallelism,如下所示:

 int myMaxDegreeOfParallelism = 4; // read this from config maybe

 Parallel.ForEach(
    list,
    new ParallelOptions
    {
        MaxDegreeOfParallelism = myMaxDegreeOfParallelism
    }
    item =>
    {
        // ... your work here ...
    });

现在,请记住,当您指定这样的最大值时,即使它们可用,也会阻止PLINQ使用更多资源。因此,如果这是在8核机器上运行,它将永远不会使用超过4个核心。相反,仅仅因为你指定4,并不意味着4保证在任何给定时间同时执行。这完全取决于TPL使用的几种启发式算法。

答案 1 :(得分:1)

这是有道理的,但我希望您知道这不是通常的方法,除非您有非常具体的性能原因或坚持使用.NET 3.5。通常,您会对列表中的元素使用Parallel.ForEach,并依赖partitioner将工作分成适当的块。

即使你没有TPL,分割所有工作并将每个线程同时交给大部分工作更为惯用,而不是在线程完成时将其分解为零碎。按你自己的方式行事的唯一原因是你预计给定工作项的时间或多或少是不可预测的,所以你不能提前把工作分开。

(另外,你可以保留对线程的引用并检查有多少线程仍在工作以及完成了多少。这将取消变量。)