最近,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; “处理任务完成”。值得阅读。阅读本文后,我可以清楚地了解它的工作原理以及何时使用这种技术。
答案 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}},除非它做得正确,没有上述问题。