【问题标题】:When to use OrderByCompletion (Jon Skeet) vs Parallel.ForEach with async delegates何时将 OrderByCompletion (Jon Skeet) 与 Parallel.ForEach 与异步委托一起使用
【发布时间】:2013-12-09 18:40:06
【问题描述】:

最近,伦敦 NDC 的 Jon Skeet 谈到了 C# 5 async/await,并提出了“按完成排序”的异步任务列表。一个链接http://msmvps.com/blogs/jon_skeet/archive/2012/01/16/eduasync-part-19-ordering-by-completion-ahead-of-time.aspx

我有点困惑,或者我应该说我不确定什么时候会更适合使用这种技术。

我无法理解此示例与以下示例之间的区别

var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, async item =>
{
  // some pre stuff
  var response = await GetData(item);
  bag.Add(response);
  // some post stuff
}

ForEachAsync 由 Stephen Toub 解释 - http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx

编辑: 发现 Stephen Toubblog post 解释了“按完成排序”“在完成任务时进行处理”。值得阅读。阅读本文后,我可以清楚地了解它的工作原理以及何时使用此技术。

【问题讨论】:

  • Parallel.ForEach 已经用于多线程。

标签: c# async-await c#-5.0


【解决方案1】:
  • 不要使用Parallel.ForEach 来执行async 代码。 Parallel.ForEach 不理解 async,所以你的 lambda 会变成 async void,这将无法正常工作(Parallel.ForEach 将在所有工作完成之前返回;异常将无法正确处理;可能还有其他问题)。

  • 当您有一组对象(不是Tasks)时,请使用ForEachAsync() 之类的东西,您想为每个对象执行一些async 操作,并且这些操作应该并行执行。

  • 当您拥有Tasks 的集合时使用OrderByCompletion(),您希望对每个Task 的结果执行一些操作(异步或非异步),这些操作应该 并行执行,并且您希望根据 Tasks 完成的顺序执行操作。

【讨论】:

  • ForEachAsync 方法记录在 Stephen Toub 的博客中。
  • @DanEsparza 是的,我没有再次链接到它,因为它已经在问题中链接到了。
【解决方案2】:
Parallel.ForEach(myCollection, async item =>

这几乎肯定不是你想要的。委托的类型为Action&lt;T&gt;,因此匿名方法是async void 方法。这意味着它被启动了,除了检查它的任何副作用之外,你无法检查它的状态。特别是,如果任何事情出错,您将无法捕获和处理异常。

不过,如果没有任何问题,结果将在完成时添加到 bag。在一切完成之前,bag 将为空。

相比之下,OrderByCompletion 返回一个IEnumerable&lt;Task&lt;T&gt;&gt;,它立即 包含所有尚未完成的任务。您可以await 第五个元素并在任何五个任务完成后继续。例如,当您想要运行大量任务并定期更新表单以显示进度时,这可能很有用。

您给出的第三个选项ForEachAsync 的行为类似于ForEach,只是它会正确执行,而不会出现上述问题。

【讨论】:

  • 如果您在文章后面查看ForEachAsync() 的版本,它们不会等待每个任务完成后再开始下一个任务。
  • @svick 啊,它有多个不同的ForEachAsync 定义,不仅在实现细节上有所不同,而且在用户可见的行为上也有所不同。谢谢,我没注意到。
猜你喜欢
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 2010-10-09
  • 2017-04-16
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多