首页 > 解决方案 > Parallel.ForEachAsync 是普通 for 循环的替代品 + 追加到任务列表(异步等待 Task.Run)+WhenAll?

问题描述

假设我想发出并行 API 发布请求。

在 for 循环中,我可以将 http post 调用附加到任务列表中(使用 Task.Run 调用的每个任务),然后等待所有人完成使用await Task.WhenAll. 因此,在等待网络请求完成时,控制权将交给调用者。实际上,API 请求将并行发出。

同样,我可以使用Parallel.ForEachAsyncwhich 将自动执行WhenAll并将控制权返回给调用者。所以我想问一下是否ForEachAsync可以替代普通的 for 循环列表(async await Task.Run)和WhenAll

标签: c#asynchronousasync-await

解决方案


不,(目前尚未发布)Parallel.ForEachAsyncAPI 与 API 的普通使用相比有很多不同之处Task.WhenAll

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

  2. 在线程(可配置Parallel.ForEachAsync上并行调用提供的异步委托。相反,使用 s 的常见模式是在当前线程上按顺序创建s。ThreadPoolTask.WhenAllTask

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

  4. Parallel.ForEachAsync一旦异步委托调用或 created 发生第一个错误,将停止调用异步委托,Task然后在等待所有已创建的任务之后传播包含到目前为止已发生的所有错误的失败。相反,使用 的常见模式Task.WhenAll是假设创建所有任务不可能中途失败,对这种可能性不采取任何预防措施,并冒着泄露即发即弃任务的风险,以防万一发生不可想象的事情。


推荐阅读