我想在F#中使用任务并行库(TPL)来执行许多(> 1000)长时间运行的任务。这是我目前的代码:
Parallel.For(1, numberOfSets, fun j ->
//Long running task here
)
当我开始这时,似乎.NET立即启动所有任务并且不断地在它们之间反弹。更好的是,如果它继续执行任务,直到完成任务,然后再转移到下一个任务。这将最小化上下文切换。
有没有办法为调度程序提供提示?我知道有可能提供提示,但我找不到明确的例子,或者调度程序已经很聪明,而且只是我认为存在太多的上下文切换。谢谢你的帮助!
答案 0 :(得分:8)
我们遇到了类似的问题 - 使用C#而不是F#,但库是相同的。解决方案是限制并行度:
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 16;
Parallel.For(0, n, parallelOptions, i => {
. . .
});
16适用于我们的任务 - 您应该尝试在您的情况下查看哪个值更好。
答案 1 :(得分:5)
根据我的经验,对于大量任务,最好将MaxDegreeOfParallelism
线性绑定到Environment.ProcessorCount
。
这是与Fimo语法中的@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#,并且它们可用here。
答案 2 :(得分: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
)。