C# Task.WhenAll和Task.WhenAny - 高效管理多个并行任务

来源:这里教程网 时间:2026-02-21 17:32:49 作者:

Task.WhenAllTask.WhenAny 是 C# 中协调多个异步任务的核心工具,它们不执行任务,而是“观察”任务的完成状态,帮你决定下一步怎么走。

Task.WhenAll:等全部跑完再继续

当你需要所有异步操作都成功完成(比如批量获取用户数据、并行上传多个文件),就用

WhenAll
。它返回一个新任务,这个任务在所有输入任务都完成后才完成;如果任一任务出错或被取消,它会立刻失败,并抛出包含所有异常的
AggregateException

传入
IEnumerable<task></task>
Task[]
,返回
Task
;传入
Task<t>[]</t>
,返回
Task<t></t>
结果数组顺序与输入顺序严格一致,哪怕实际完成顺序不同 注意异常处理:建议用
try/catch
捕获
AggregateException
,再遍历
InnerExceptions
分析具体失败项

Task.WhenAny:谁先回来就先处理谁

适合“抢答”场景,比如设置超时、从多个服务中取最快响应、或实现降级逻辑。它返回一个

Task<task></task>
,里面包裹最先完成的那个原始任务(无论成功、失败还是取消)。

拿到结果后,要 await 那个内部 Task 才能真正读取值或捕获异常 其余未完成的任务不会自动取消,需手动调用
CancellationTokenSource.Cancel()
或保留引用后续处理
常配合
Task.Delay()
实现超时控制,例如:
await Task.WhenAny(apiCall, Task.Delay(3000)) == apiCall ? ... : "超时"

别混淆:它们不是并发执行器

WhenAll
WhenAny
本身不启动任务——你得先调用异步方法(如
GetDataAsync()
)拿到
Task
对象,再把它们传进去。常见错误是写成
WhenAll(GetDataAsync(), GetDataAsync())
,这其实是同步调用两次,不是并行发起。

正确做法:先创建任务列表,再统一传入
WhenAll
示例:
var tasks = urls.Select(u => HttpClient.GetAsync(u)); await Task.WhenAll(tasks);
若想限制并发数(比如最多同时请求 5 个),要用
SemaphoreSlim
Parallel.ForEachAsync
(.NET 6+)

选哪个?看你的业务意图

问自己一个问题:“我关心的是所有结果,还是第一个结果?”

要汇总、校验、批量提交 → 选
WhenAll
要快速响应、容错降级、避免等待 → 选
WhenAny
两者可嵌套使用,比如用
WhenAny
控制整体超时,内部用
WhenAll
并行拉取子数据

基本上就这些。用对了,异步代码既清晰又健壮。

相关推荐