7

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

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

当我开始这个时,似乎 .NET 会立即启动所有任务并不断在它们之间反弹。更好的是,如果它一直执行一项任务,直到它完成,然后再进行下一个任务。这将最小化上下文切换。

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

4

3 回答 3

8

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

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

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

于 2012-11-24T18:56:15.583 回答
5

根据我的经验,对于大量任务,最好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# 进行并行编程,请查看优秀的书籍“使用 Microsoft .NET 进行并行编程”,尤其是“并行循环”一章。@Tomas 已将其示例翻译为 F#,可在此处获得。

于 2012-11-25T01:48:50.767 回答
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内部长时间运行的任务)。

于 2012-11-25T10:38:32.110 回答