是平行的.ForEachAsync替换为普通的for循环+附加到任务列表(async await task . run)



假设我想进行并行API post请求。

在for循环中,我可以将http post调用附加到任务列表中(每个任务使用task . run调用),然后等待所有任务使用await Task.WhenAll完成。因此,在等待网络请求完成时,控件将转到调用方。实际上,API请求将并行进行。

同样,我可以使用Parallel.ForEachAsync,它将自动执行WhenAll并将控制权返回给调用者。所以我想问ForEachAsync是否取代了一个普通的循环列表(异步等待任务运行)和WhenAll?

不,与Task.WhenAllAPI的简单使用相比,Parallel.ForEachAsyncAPI有很多不同之处:

  1. 房间里的大象:await Task.WhenAll返回一个包含异步操作结果的数组。相反,Parallel.ForEachAsync返回一个裸Task。如果你想要这样的结果,你必须依赖于副作用,比如更新ConcurrentQueue<T>作为异步操作的一部分。

  2. Parallel.ForEachAsyncThreadPool线程(可配置)上并行调用提供的异步委托。相反,使用Task.WhenAll的常见模式是在当前线程上依次创建Task。这引起了对在ASP中使用Parallel.ForEachAsync的关注。. NET应用程序,其中卸载ThreadPool上的工作可能会影响可伸缩性。

  3. Parallel.ForEachAsync调用异步委托并等待生成的任务,同时强制执行与Environment.ProcessorCount相等的最大并发级别。此行为可通过MaxDegreeOfParallelism选项进行配置。相反,使用Task.WhenAll的常见模式是一次创建所有任务,不施加并发性限制。

  4. 使用Task.WhenAll的常见模式是假设创建所有任务不可能中途失败,因此不采取任何预防措施来防止这种可能性。如果这种情况真的发生了,"即炒即弃"的任务可能会被泄露。这在Parallel.ForEachAsyncAPI中是不可能的。

  5. 在异步委托调用或创建的Task上发生第一个错误时,Parallel.ForEachAsync将停止调用异步委托,然后在等待所有已经创建的任务之后,传播包含到目前为止发生的所有错误的失败。它还提供了一种机制,用于在错误发生时取消正在执行的其他任务(作为lambda中的第二个参数传递的CancellationToken)。相反,Task.WhenAll总是等待所有任务完成。这意味着您可能需要等待更长的时间,才能最终收到包含所有失败任务错误的AggregateException

最新更新