2

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

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
4

2 回答 2

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 使用的几种启发式方法是最优的。

于 2011-03-03T00:51:09.530 回答
1

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

即使您没有 TPL,将所有工作分开并一次性交给每个线程一大块工作,而不是在线程完成的那一刻零碎地分发它会更惯用。这样做的唯一原因是,如果您预计给定工作项所花费的时间或多或少不可预测,因此您无法提前很好地划分工作。

(此外,您可以只保留对线程的引用并检查有多少仍在工作以及有多少已完成。这将消除变量。)

于 2011-03-02T22:08:02.823 回答