何时使用OrderByCompletion(Jon Skeet)和Parallel.ForEach与异步委托

时间:2013-12-09 18:40:06

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

最近,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
}
由Stephen Toub解释的

ForEachAsync - http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx

  

编辑 Stephen Toub 找到blog post,解释“按完成排序”&lt; =&gt; “处理任务完成”。值得阅读。阅读本文后,我可以清楚地了解它的工作原理以及何时使用这种技术。

2 个答案:

答案 0 :(得分:15)

  • 请勿使用Parallel.ForEach执行async代码。 Parallel.ForEach无法理解async,因此您的lambda将变为async void,这将无法正常工作(Parallel.ForEach将在所有工作完成之前返回;不妥善处理;可能还有其他问题。)

  • 当你有一组对象(不是ForEachAsync() s)时,使用类似Task的内容,你想为每个对象执行一些async操作,并且应该采取措施并行执行。

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

答案 1 :(得分:2)

Parallel.ForEach(myCollection, async item =>

这几乎肯定不是你想要的。委托的类型为Action<T>,因此匿名方法是async void方法。这意味着它会被启动,除了通过检查其任何副作用之外,你无法检查其状态。特别是,如果任何出错,则无法捕获并处理异常。

假设没有出错,结果将在bag完成后添加到bag。在任何事情完成之前,OrderByCompletion将为空。

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

您提供的第三个选项ForEach的行为类似于{{1}},除非它做得正确,没有上述问题。