我应该为ForEachAsync扩展方法指定什么Dop参数?
本文关键字:什么 Dop 参数 ForEachAsync 扩展 方法 我应该 | 更新日期: 2023-09-27 18:19:07
我最近发现下面的代码可以有效地运行大量的I/O绑定任务:
实现一个简单的ForEachAsync,第2部分
在我的印象中,下列情况是正确的:
- 这比使用
Parallel.ForEach
要好得多,因为工作不受CPU限制。 - TPL将"知道"这些是基于IO的任务,而不是启动更多的线程,而是使用回调/任务完成源向主线程发送信号,从而节省线程上下文切换的开销。
ForEachAsync
将帮助将尽可能多的IO任务排队(不必将它们放在单独的线程上)。我的问题是,由于Parallel.ForEach
本质上有自己的MaxDegreeOfParallelism
定义,我如何知道在IEnumerable
扩展的示例代码中定义dop参数到这里?
。如果我有1000个项目要处理,并且需要为每个项目执行基于IO的SQL-Server db调用,我会指定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);
}));
}
平行。ForEach本质上有自己的MaxDegreeOfParallelism
好的,Parallel.ForEach
内置的启发式很容易随着时间的推移产生大量的任务(如果你的工作项有10ms的延迟,你会在一个小时左右得到数百个任务——我测量过)。真的很糟糕的设计缺陷,不要试图模仿这个。
当并行运行IO时,没有什么可以替代经验确定正确的值。这就是为什么TPL在这方面如此糟糕。例如,执行顺序IO的磁盘的DOP为1。一个随机的SSD基本上是无限的(100?)。
远程web服务无法让您知道正确的DOP。你不仅需要测试,你还需要请求所有者允许你向服务发送可能会使其过载的请求。
我将指定1000作为dop吗?
那么你就根本不需要这个设施了。只需要刷出所有任务,然后等待所有任务完成。但是1000可能是错误的DOP,因为它压倒了DB而没有任何好处。
这里似乎是用来划分异步任务的最小数量
Parallel.For
的另一个可怕的特性。在低CPU机器上,它可能会生成小的任务。可怕的API。不要与IO一起使用。(我使用AsParallel
,它允许您设置精确 DOP,而不是最大DOP。)
因为我想让尽可能多的基于IO的数据库调用排队
为什么?不是个好计划。
顺便说一句,你贴在这里的方法很好,我也用这个。我希望它在框架中。这种确切的方法是每周大约1050个问题("我如何并行异步处理100000个项目?")的答案。