C# Async/Await使用疑问:是否需等待异步任务完成再合并结果
结论
你当前的Async/Await写法不是最高效实现,且结果合并操作必须等两个异步任务全部执行完成后才能执行。
现有实现的性能问题
你现在写的两个await是串行执行逻辑:代码执行到第一个await GetAdHocReports(days)时,会等待该方法完全返回结果后,才会启动GetPushReports(days)的调用。这两个查询操作互相没有依赖,完全可以并发执行,串行等待会白白多消耗一倍左右的IO等待时间。
合并操作的时机要求
必须等两个任务全部执行完成后再合并结果。合并逻辑需要拿到两个查询返回的完整数据集,任意一个任务没完成都无法拿到完整数据做合并,提前操作要么会阻塞线程,要么会抛出异常、拿到不完整结果。
优化后的高效实现
先同时启动两个异步任务,再通过Task.WhenAll等待两个任务全部完成后做结果合并即可,优化后总耗时约等于两个查询中耗时更长的那个,而非两个查询耗时的总和,参考代码:
public async Task<IEnumerable<Reports>> GetReports(int days = 0) { // 同时启动两个异步查询任务,不立即等待 var adHocReportsTask = GetAdHocReports(days); var pushReportsTask = GetPushReports(days); // 等待两个任务全部执行完成 await Task.WhenAll(adHocReportsTask, pushReportsTask); // 两个任务均已完成,直接取结果合并无额外阻塞 var result = new List<Reports>(); result.AddRange((List<Reports>)adHocReportsTask.Result); result.AddRange((List<Reports>)pushReportsTask.Result); return result; }
注意事项
- 如果你的数据库连接没有开启MARS(多活动结果集),同一个连接不支持同时执行多个查询,这种场景下并发执行会抛出异常,此时保留原有的串行await写法即可。
- 不要在
Task.WhenAll执行完成前调用任务的Result属性,否则会阻塞当前线程,失去异步的优势。
内容的提问来源于stack exchange,提问作者user17176542
相关产品推荐
相关产品推荐

