何时使用OrderByCompletion(Jon Skeet)和Parallel.ForEach与异步委托
最近,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(); 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的博客文章解释“按完成排序”“处理完成后的任务”。 值得阅读。 阅读本文后,我可以清楚地了解它的工作原理以及何时使用这种技术。
-
不要使用
Parallel.ForEach
来执行async
代码。Parallel.ForEach
不理解async
,因此你的lambda将变成async void
,这将无法正常工作(Parallel.ForEach
将在所有工作完成之前返回;exception将无法正确处理;可能还有其他问题)。 -
当你有一个对象集合(而不是
Task
ForEachAsync()
时,使用类似ForEachAsync()
东西,你想为每个对象执行一些async
操作,并且这些操作应该并行执行。 -
当你有一个
Task
集合时,使用OrderByCompletion()
,你想为每个Task
的结果执行一些操作(异步或非异步),这些操作不应该并行执行,你想根据顺序执行动作Task
完成。
Parallel.ForEach(myCollection, async item =>
这几乎肯定不是你想要的。 委托具有Action
类型,因此匿名方法是async void
方法。 这意味着它会被启动,除了通过检查其任何副作用之外,你无法检查其状态。 特别是,如果出现任何问题,您将无法捕获并处理exception。
但是,假设什么都没有出错,结果会在完成后添加到bag
中。 在任何事情完成之前, bag
将是空的。
相反, OrderByCompletion
返回一个IEnumerable
,它立即包含所有尚未完成的任务。 您可以await
第五个元素,并在任何五个任务完成后继续。 例如,当您想要运行大量任务并定期更新表单以显示进度时,这可能很有用。
你给出的第三个选项, ForEachAsync
,就像ForEach
一样,除非它做得正确,没有上面提到的问题。