C#手动创建Task与调用Task.Run的差异及多Task并行等待问题
问题根因
你遇到的问题本质是new Task()构造方法传入异步lambda时的嵌套Task问题:
- 你的
DoSomeMagic是返回Task的异步方法,new Task(() => DoSomeMagic())实际构造的是Task<Task>类型(外层Task代表执行lambda的过程,内层Task才代表DoSomeMagic的完整执行生命周期) - 你将外层
Task<Task>隐式转换为Task存入列表后,Task.WaitAll只会等待外层Task执行完成:外层Task在执行到DoSomeMagic内部第一个await时就会返回,此时内层Task还没执行完,所以就出现了主线程提前继续执行的问题,编译器的警告也正是在提示你没有等待异步调用的返回结果。
解决方案
方案1:给第一种写法增加Unwrap解包
你只需要将嵌套的Task<Task>解包,拿到代表DoSomeMagic完整执行的内层Task即可,修改代码如下:
List<Task> TaskList = new List<Task>(); // 显式指定返回Task的泛型构造,调用Unwrap解包得到内层实际执行任务 var LastTask = new Task<Task>(() => DoSomeMagic()).Unwrap(); LastTask.Start(); TaskList.Add(LastTask); Task.WaitAll(TaskList.ToArray());
修改后Task.WaitAll就会等待DoSomeMagic内部所有逻辑执行完成,警告也会自动消失。
方案2:修正对Task.Run的误解,批量并行添加任务
你之前认为“Task.Run无法实现并行多线程”是错误的,Task.Run本身就是将任务提交到线程池调度执行,你完全可以批量将多个任务添加到列表实现并行执行,Task.Run传入异步lambda时会自动帮你做Unwrap操作,代码更简洁不易出错:
List<Task> TaskList = new List<Task>(); // 批量添加多个并行任务,不会逐个执行 TaskList.Add(Task.Run(() => DoSomeMagic())); TaskList.Add(Task.Run(() => DoSomeOtherMagic())); // 可添加任意数量的任务 Task.WaitAll(TaskList.ToArray());
额外建议
如果你的外层调用逻辑支持异步写法,优先用await Task.WhenAll(TaskList)代替Task.WaitAll,可以避免阻塞当前线程,减少死锁风险。
内容的提问来源于stack exchange,提问作者Stefan Taseski
相关产品推荐
相关产品推荐

