为什么Task.WhenAll要求手动创建的Task启动,异步方法返回的则不需要?
核心差异原因:两种方式获取的Task的创建逻辑和初始状态完全不同
1. 用new Task(...)构造出来的是冷任务(Cold Task)
你调用new Task(Func/Action)构造方法时,仅仅是在内存里创建了一个Task对象,并没有把它调度到线程池执行,它的初始状态是Created。
- 如果你不手动调用
Start()方法,这个Task永远不会被执行,状态也永远不会变更为RanToCompletion/Faulted/Canceled,Task.WhenAll会无限等待这个永远不会完成的任务,自然会导致程序永久挂起。 - 额外补充你代码里隐藏的坑:
new Task(async () => {...})的重载接收的是Action参数,你传入的async lambda会被隐式转换为async void,这个构造返回的外层Task只会追踪到lambda第一次遇到await返回前的同步执行逻辑,不会追踪内部await的异步操作,哪怕你调用了Start(),外层Task也会在Task.Delay(2000)触发await的时候就标记为完成,不会等2秒后的输出逻辑执行完。如果要正确追踪异步委托的执行,应该用Task.Run(async () => {...}),这个方法会自动拆包内层的Task,返回的Task能完整追踪整个异步逻辑的执行。
2. 调用async方法返回的是热任务(Hot Task)
所有被async关键字修饰的方法,只要你发起调用,方法体就会立刻开始执行,返回的Task对象默认已经处于调度/执行状态,不需要你手动调用Start()触发。
你代码里调用SubDo1()的瞬间,方法里的Task.Delay(2000)就已经开始倒计时,返回的Task本身就是已经在运行的状态,Task.WhenAll只需要等待它执行完成即可,自然不需要额外的启动操作。
内容的提问来源于stack exchange,提问作者AmandaSai98b
相关产品推荐
相关产品推荐

