Python asyncio创建Task后未用await的执行行为疑问
关于asyncio Task执行逻辑的疑问
我正在学习asyncio,对Task的执行逻辑存在疑惑。已知当当前协程挂起、控制权交还给事件循环时,Task会开始执行。但如果创建Task后从未调用await,协程直接退出会发生什么?
示例代码
import asyncio async def print_stuff(s): print(s) async def print_wrapper(s): print(f"{s}: create task") asyncio.create_task(print_stuff(s)) print(f"{s}: sleeping") print(f"{s}: ending coroutine") async def sleep_wrapper(s): print(f"{s}: before sleep") await asyncio.sleep(2) print(f"{s}: after sleep") async def main(): asyncio.create_task(print_stuff("stuff")) asyncio.create_task(print_wrapper("wrapper")) asyncio.create_task(sleep_wrapper("abc")) asyncio.run(main()) print("after main")
运行输出
stuff wrapper: create task wrapper: sleeping wrapper: ending coroutine abc: before sleep after main
疑问
- 为何main结束后仍能看到Task的输出?事件循环不是应该随main结束而终止吗?
- 为何"wrapper"内部创建的Task输出和"abc: after sleep"未被打印,而其他信息却正常输出?
问题解答
1. main结束后仍有Task输出的原因
asyncio.run(main())的逻辑是:启动事件循环,运行main协程,当main协程执行完毕(它内部没有任何await,同步执行完所有create_task就结束了),事件循环并不会立刻终止——它会先把当前已就绪的Task调度执行一遍,直到没有可直接运行的Task,或者遇到需要等待的挂起操作,才会终止。
你看到的输出里:
print_stuff("stuff")这个Task没有任何await操作,创建后就处于就绪状态,所以在main结束后,事件循环会优先调度它执行,打印出stuff。print_wrapper里的打印语句都是同步执行的,不需要挂起,所以在print_wrapper协程自身执行过程中就直接输出了,和事件循环是否终止无关。sleep_wrapper里的before sleep也是同步代码,在执行到await asyncio.sleep(2)之前就完成了输出,这时候该Task才会挂起。
2. 未打印内容的原因
- wrapper内部创建的Task没输出:
print_wrapper里创建的print_stuff(s)确实被加入了事件队列,但事件循环在main结束后,先处理的是main直接创建的三个Task:print_stuff("stuff")执行完毕,print_wrapper执行完毕,sleep_wrapper执行到await sleep处挂起。此时事件循环检查任务队列,发现没有其他就绪的Task(wrapper内部的Task虽然存在,但事件循环在终止前没有机会调度它),就直接停止了,导致这个Task从未被执行。 - abc: after sleep没输出:
await asyncio.sleep(2)会让sleep_wrapper这个Task挂起2秒,而事件循环不会等待挂起的Task唤醒——当所有就绪Task都处理完后,事件循环就会终止,所以这个挂起的Task永远没机会恢复执行,自然不会打印after sleep。
内容的提问来源于stack exchange,提问作者ting.c
相关产品推荐
相关产品推荐

