【问题标题】:Process a list of items using multiple, limited number of threads使用多个有限数量的线程处理项目列表
【发布时间】:2011-03-02 22:04:02
【问题描述】:

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

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

【问题讨论】:

  • 这种机制来自 .NET 4.0 的 OOTB。 :)
  • 为什么要控制线程数?使用Threadpool 让框架做出最佳决策。
  • 所以我可以遍历列表并在每个项目上使用 QueueUserWorkItem 而不必担心有多少线程正在运行?游泳池会为我管理吗?有趣...

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2015-08-19
      • 2016-01-01
      • 1970-01-01
      • 2021-10-27
      • 2011-07-17
      • 1970-01-01
      • 2013-03-11
      • 2020-11-16
      • 1970-01-01
      相关资源
      最近更新 更多