TPL Parallel.For 使用长时间运行的任务

7

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

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

当我启动此程序时,似乎.NET会立即启动所有任务,并不断在它们之间反弹。更好的做法是,在移动到下一个任务之前,应该待在当前任务上直到完成。这将最小化上下文切换。
有没有办法向调度程序提供提示?我知道可以提供提示,但是我找不到清晰的例子,或者是调度程序已经很聪明了,只是我的感觉有太多的上下文切换正在发生。感谢您的帮助!
3个回答

8
我们遇到了类似的问题——使用C#而不是F#,但是库相同。 解决方法是限制并行度:
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 16;
Parallel.For(0, n, parallelOptions, i => {
   . . . 
});

对于我们的任务来说,16表现良好——您应该尝试确定在您的情况下哪个值更好。


最大并行度是否应该取决于您计算机上的核心数量? - Matthew Crews
@Wallhood:如果任务是CPU密集型的话,很可能会有所帮助;但如果任务是IO密集型的(如文件处理、访问数据库),那么就不一定了。在我们的情况下,在正常情况下2/4个核心的值已经足够了,没有必要尝试更复杂的方法——毕竟这不是一个可能在16核超级计算机上运行的程序。 - MiMo
@MiMo:我有一台4核心的机器,我将MaxDegreeOfParallelism设置为4,它运行得非常好。任务纯粹是CPU密集型的,因此最小化上下文切换确实加快了速度。感谢您的帮助! - Matthew Crews
3
@Wallhood,你可以将MaxDegreeOfParallelism设置为System.Environment.ProcessorCount而不是硬编码数值。但是由于超线程,你可能需要将处理器数量除以2。 - Jack P.
@JackP:谢谢!那正是我接下来要寻找的东西。 - Matthew Crews

5

根据我的经验,在处理大量任务时,最好将MaxDegreeOfParallelism线性限制为Environment.ProcessorCount

以下是F#语法中类似于@Mimo的代码片段:

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#,可在此处获取


1

从参考源代码来看,以下代码段确定了工人的数量:

// 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)。

有很大的差别。当我指定最大并发数时,每个核心只会同时打开一个任务。当我没有指定时,它会一次性打开所有任务。它可能只是一次处理一个任务,但确实将它们全部打开了。我是根据为每个任务启动计时器这一事实推断出来的。当我指定并行度时,每个任务的时间都相同。当我没有指定时,任务完成可能需要很长时间。底层发生了什么,我不知道,但这些是我的观察结果。 - Matthew Crews
也许工作人数和 MaxDegreeOfParallelism 是两回事?我确认 @Wallhood 所说的:当我们有成千上万个任务时,如果不设置 MaxDegreeOfParallelism,它们似乎都会并行启动并且会使机器崩溃。将其设置为 16 后问题得到了解决(我们的任务不是 CPU 密集型,而是主要与数据库绑定)。 - MiMo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接