foreach循环与Task.WhenAll的区别:为何后者提升异步代码性能?
异步循环优化:Task.WhenAll 为何比普通 foreach 性能更高?
原串行代码
foreach (var name in names) { var some = await SomeMethodAsync1(name); await SomeMethodAsync2(name); //... }
优化后的并行代码
var tasks = names.Select(async n => { var some = await SomeMethodAsync1(n); await SomeMethodAsync2(n); //... }).ToList(); await Task.WhenAll(tasks);
核心区别与性能提升原因
原代码是完全串行执行:
处理每个name时,必须等当前name的SomeMethodAsync1完成,再执行SomeMethodAsync2,所有操作结束后才会开始处理下一个name。总耗时等于所有name的异步操作耗时之和。优化后是多任务链并行执行:
调用Select并ToList时,每个name对应的异步任务链会被立即启动(lambda中的SomeMethodAsync1(n)会立刻开始执行)。虽然单个name内部的await保证了SomeMethodAsync1在SomeMethodAsync2之前完成,但不同name的任务链是同时运行的。最后用Task.WhenAll等待所有任务链结束,总耗时接近耗时最长的那个任务链的时间,而非所有任务耗时的总和,因此性能大幅提升。
简单来说,前者是一个接一个排队做事,后者是同时启动多组任务各自做事,最后等所有组完成,自然效率更高。
内容的提问来源于stack exchange,提问作者Андрей
相关产品推荐
相关产品推荐

