我指定什么作为ForEachAsync扩展方法的Dop参数?

时间:2015-10-25 22:01:46

标签: c# .net multithreading async-await task-parallel-library

我最近发现了以下代码,可以有效地运行大量的IO绑定任务(参见链接)。 http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx

我认为以下情况属实:

  • 这比使用Parallel.ForEach要好得多,因为工作不受CPU限制。
  • ForEachAsync将帮助排队尽可能多的IO任务(不必将这些任务放在不同的线程上)。
  • TPL将会知道'这些是基于IO的任务,而不是更多线程,而是使用回调/任务完成源来发回主线程,从而节省了线程上下文切换的开销。

我的问题是,由于Parallel.ForEach本身有自己的MaxDegreeOfParallelism,我如何知道在IEnumerable扩展的示例代码中定义dop参数的内容?

e.g。如果我要处理1000个项目并且需要为每个项目执行基于IO的SQL-Server数据库调用,我是否将1000指定为 dop ?使用Parallel.ForEach,它被用作限制器,以防止过多的线程旋转,这可能会损害性能。但在这里它似乎用于分区最小数量的异步任务。我认为应该至少没有最大值(最小值是要处理的总项数),因为我想尽可能多地对数据库进行基于IO的调用。

我如何知道如何查看DOP参数?

public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body) 
{ 
    return Task.WhenAll( 
        from partition in Partitioner.Create(source).GetPartitions(dop) 
        select Task.Run(async delegate { 
            using (partition) 
                while (partition.MoveNext()) 
                    await body(partition.Current); 
        })); 
}

1 个答案:

答案 0 :(得分:3)

  

Parallel.ForEach本身就有自己的MaxDegreeOfParallelism

好吧,Parallel.ForEach内置的启发式方法很容易随着时间的推移产生大量的任务(如果你的工作项目延迟10毫秒,你会在一小时左右后得到数百个任务 - 我测量了它)。真的很糟糕的设计缺陷,不要试图模仿这个。

当并行运行IO时,无法用经验确定正确的值。这就是为什么TPL如此糟糕。例如,执行顺序IO的磁盘喜欢DOP为1.执行随机的SSD基本上是无限的(100?)。

远程网络服务让您无法知道正确的DOP。您不仅需要进行测试,还需要向所有者请求允许使用可能使其超载的请求来垃圾邮件服务。

  

我会指定1000作为dop吗?

然后你根本不需要这个设施。只产生所有任务,然后等待所有任务。但1000可能是错误的DOP,因为它没有任何好处压倒DB。

  

这里似乎用于分区最小数量的异步任务

Parallel.For的另一个可怕特征。在低CPU机器上,它可能会产生 little 任务。可怕的API。 将其与IO一起使用。 (我使用AsParallel允许您设置完全 DOP,而不是最大DOP。)

  

因为我希望尽可能多地对数据库进行基于IO的调用

为什么?不是一个好的计划。

顺便说一下,你在这里发布的方法很好,我也使用它。我希望它在框架中。这个确切的方法是每周大约10个SO问题的答案(&#34;我如何异步处理100000项并行处理?&#34;)。