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

use*_*872 5 .net c# multithreading task-parallel-library async-await

我最近发现了以下代码,可以有效地运行大量的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参数的内容?

例如,如果我要处理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); 
        })); 
}
Run Code Online (Sandbox Code Playgroud)

usr*_*usr 4

Parallel.ForEach 本质上有自己的 MaxDegreeOfParallelism

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

并行运行 IO 时,无法替代凭经验确定正确的值。这就是TPL在这方面如此糟糕的原因。例如,执行顺序 IO 的磁盘喜欢 DOP 为 1。执行随机的 SSD 喜欢基本上无限(100?)。

远程 Web 服务无法让您知道正确的 DOP。您不仅需要测试,还需要请求所有者允许向服务发送垃圾邮件,这些请求可能会导致服务过载。

我会指定 1000 作为 dop 吗?

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

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

的另一个可怕的功能Parallel.For。在 CPU 较低的机器上,它可能会产生一些任务。可怕的 API。不要其与 IO 一起使用。(我使用AsParallel它允许您设置精确的DOP,而不是最大 DOP。)

因为我想对尽可能多的基于 IO 的数据库调用进行排队

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


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