在Parallel.ForEach中指定默认的最大并行度?

3
我们希望能够可选地控制并行循环中的“线程”数量,以避免使Web服务(例如)过载。
在Parallel.ForEach循环中指定自定义MaxDegreeOfParallelism是否可行,并根据需要恢复默认值?看起来,零(0)是无效的MaxDegreeOfParallelism值,而我希望它只是表示“忽略”。
换句话说,您能否避免编写此类型的代码?
int numParallelOperations = GetNumParallelOperations();
if (numParallelOperations > 0)
{
 ParallelOptions options = new ParallelOptions();
 options.MaxDegreeOfParallelism = numParallelOperations;
 Parallel.ForEach(items, options, i => 
 {
   Foo(i);
 });
}
else
{ 
 Parallel.ForEach(items, i => 
 { 
   Foo(i);
 });
}

2
答案是根据这里的说明使用负一(-1)。(http://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.maxdegreeofparallelism%28v=vs.110%29.aspx) - PeterX
我已经编辑了你的标题。请参考“问题标题应该包括‘标签’吗?”,其共识是“不应该”。 - John Saunders
你是指根据MSDN的说明,-1的意思是:MaxDegreeOfParallelism限制了由传递给此ParallelOptions实例的Parallel方法调用运行的并发操作数,如果它是正数,则设置为该值。如果MaxDegreeOfParallelism为-1,则不会对同时运行的操作数量施加限制。 - TaW
所以请确保GetNumParallelOperations始终返回大于或等于-1的值。这样,您就不需要条件语句了。GetNumParallelOperations可以从配置文件中读取该值,并在找不到该设置时提供合理的默认值。 - Jim Mischel
2个回答

8
你是指根据MSDN-1的含义如下:
MaxDegreeOfParallelism限制了通过传递此ParallelOptions实例的Parallel方法调用运行的并发操作数,如果它是正数,则为设置值。 如果MaxDegreeOfParallelism为-1,则不会对同时运行的操作数量进行限制。
你可以像这样控制大致线程数:
// use only (ca) one kernel:
int degreeOfParallelism = 1;
// leave (ca) one kernel idle:
int degreeOfParallelism = Environment.ProcessorCount - 1;
// use (ca) half of the kernels:
int degreeOfParallelism = Environment.ProcessorCount > 1 ? 
                          Environment.ProcessorCount / 2 : 1;
// run at full speed:
int degreeOfParallelism =  - 1;

var options = new ParallelOptions();
options.MaxDegreeOfParallelism = degreeOfParallelism;

Parallel.For(0, x, options, y => 
//...

6
那么问题是,-1和不设置选项是否相同? - PeterX
2
是的。据我理解,您想要一个统一的调用,对吗?此外,您可能需要为其他成员(如“CancellationToken”)使用选项 - TaW
什么是统一调用?我没有必要设置其他选项就能让它正常工作。 - PeterX
ParallelOptions.MaxDegreeOfParallelism链接 的英文MSDN页面。 - Issung

2

由于我刚加入StackOverflow,无法添加评论,因此我的回答可能不是最终答案。我认为你所要求的是不可能实现的,但我知道MSDN文档指出-1是设置要运行的任务数不受限制的参数。根据我的经验,最好让CLR决定并发任务的数量,除非你真的知道自己在做什么。Parallel库是高级别的,如果你需要真正做这样的事情,你应该在更低的级别上编码,并控制自己的线程,而不是把它留给TaskScheduler或ThreadPool等,但这需要大量的实验才能使你的算法有效地运行。

我唯一能建议的是,将Parallel.ForEach方法封装起来,包括设置ParallelOptions.MaxDegreeOfParallism以减少重复代码,并使你能够添加一个接口并以同步方式测试异步代码。

很抱歉不能提供更积极的回答!


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