【问题标题】:TPL Parallel.For with long running tasksTPL Parallel.For 具有长时间运行的任务
【发布时间】:2012-11-24 18:50:11
【问题描述】:

我想使用 F# 中的任务并行库 (TPL) 来执行许多 (>1000) 长时间运行的任务。这是我当前的代码:

Parallel.For(1, numberOfSets, fun j ->
    //Long running task here
    )

当我启动它时,似乎 .NET 会立即启动所有任务并在它们之间不断跳动。更好的是,如果它一直执行一项任务,直到它完成,然后再转移到下一个任务。这将最大限度地减少上下文切换。

有没有办法向调度程序提供提示?我知道可以提供提示,但是我找不到明确的示例,或者调度程序对此是否已经很聪明,这只是我的看法,即发生了太多的上下文切换。感谢您的帮助!

【问题讨论】:

    标签: .net f# parallel-processing task-parallel-library


    【解决方案1】:

    我们遇到了类似的问题 - 使用 C# 而不是 F#,但库是相同的。解决方案是限制并行度:

    ParallelOptions parallelOptions = new ParallelOptions();
    parallelOptions.MaxDegreeOfParallelism = 16;
    Parallel.For(0, n, parallelOptions, i => {
       . . . 
    });
    

    16 对我们的任务很有效 - 您应该尝试看看哪个值更适合您的情况。

    【讨论】:

    • MaxDegreeOfParallelism 是否应该取决于您机器上的内核数?
    • @Wallhood:如果任务受 CPU 限制,可能是,如果任务受 IO 限制(文件处理,访问数据库)可能不是。在我们的案例中,在正常情况下,该值在 2/4 核上运行良好,没有真正的理由尝试更复杂的东西 - 例如,它不是一个可能在 16 核超级机器上运行的程序。跨度>
    • @MiMo:我有一台 4 核机器,我将 MaxDegreeOfParallelism 设置为 4,它运行良好。这些任务纯粹受 CPU 限制,因此最小化上下文切换确实可以加快速度。感谢您的帮助!
    • @Wallhood 可以将MaxDegreeOfParallelism 设置为System.Environment.ProcessorCount,而不是对值进行硬编码。不过,您可能需要将处理器数量除以 2 以考虑超线程。
    • @JackP.:谢谢!那是我接下来要寻找的东西。
    【解决方案2】:

    根据我的经验,对于大量任务,最好将MaxDegreeOfParallelism 线性绑定到Environment.ProcessorCount

    下面是与@Mimo 的 F# 语法类似的代码片段:

    let options = ParallelOptions()
    options.MaxDegreeOfParallelism <- Environment.ProcessorCount * 2
    
    Parallel.For(0, n, options, 
                 (fun i -> (* Long running task here *))) |> ignore
    

    由于您正在使用 F# 进行并行编程,请查看优秀的书籍 "Parallel Programming with Microsoft .NET",尤其是关于 "Parallel Loops" 的章节。 @Tomas 已将其示例翻译为 F#,并且可以通过 here 获取。

    【讨论】:

      【解决方案3】:

      查看参考源,似乎以下代码决定了工人的数量:

      // initialize ranges with passed in loop arguments and expected number of workers 
      int numExpectedWorkers = (parallelOptions.EffectiveMaxConcurrencyLevel == -1) ?
          Environment.ProcessorCount : 
          parallelOptions.EffectiveMaxConcurrencyLevel; 
      

      据我所知,使用默认的任务调度程序和默认的 ParallelOptions,它的计算结果为 Environment.ProcessorCount,所以很奇怪你通过自己指定 MaxDegreeOfParallelism 来获得不同的行为处理器计数。我建议您调试以确保确实存在差异(您可以在长时间运行的任务中打印Thread.ManagedThreadId)。

      【讨论】:

      • 有很大的不同。当我指定最大并发时,每个核心一次只会打开一个任务。当我没有指定它时,它会一次打开所有任务。它可能一次只能处理一个,但确实让它们都打开了。我从我为每个任务启动计时器这一事实推断出这一点。当我指定并行度时,每个任务的时间是相同的。如果我不这样做,这些任务可能需要很长时间才能完成。下面发生了什么,我不知道,但这是我的观察。
      • 也许工人数量和MaxDegreeOfParallelism 是两个不同的东西?我确认@Wallhood 所说的:没有设置MaxDegreeOfParallelism,当我们有1000 个任务时,它们似乎都是并行启动并且它们正在阻塞机器,问题已修复,将其设置为16(我们的任务不是CPU,但主要是数据库绑定)
      猜你喜欢
      • 1970-01-01
      • 2012-02-11
      • 1970-01-01
      • 2015-07-06
      • 1970-01-01
      • 2019-02-20
      • 2015-11-29
      • 2012-08-13
      • 2022-01-01
      相关资源
      最近更新 更多