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

时间:2012-11-24 18:50:12

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

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

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

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

有没有办法为调度程序提供提示?我知道有可能提供提示,但我找不到明确的例子,或者调度程序已经很聪明,而且只是我认为存在太多的上下文切换。谢谢你的帮助!

3 个答案:

答案 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)。