asyncio.create_task未await结果与gather执行差异及异常原因问询
asyncio 相关问题解答
问题1:create_task 与 gather 的执行差异及 gather 抛异常的原因
核心触发点是你的代码中 asyncio.gather 调用前没有加await,具体逻辑拆解如下:
create_task调用后,对应任务会被立刻提交到当前事件循环的调度队列,只要事件循环正常运行就会被分配时间片执行。你开头创建的3个create_task任务执行到await asyncio.sleep(1)时会让出CPU,事件循环随即调度后续代码逻辑。asyncio.gather本身是协程函数,接收的参数如果是原生协程对象,会自动把协程包装成Task提交到事件循环调度,所以你又生成了3个新的sleep_and_print任务——这就是输出中有6条「开始执行」日志的原因:3条来自开头的create_task,3条来自gather自动包装的任务。- 抛出
CancelledError的原因:你没有awaitgather协程,main函数在创建完gather对应的协程对象后直接执行结束,asyncio.run(main())会在main返回后自动关停事件循环,关停前会取消所有未完成的运行中任务,包括前面创建的3个Task、gather自动创建的3个Task,以及gather本身的Future对象,未被捕获的取消事件就抛出了对应异常,所有任务都卡在await asyncio.sleep(1)的位置,没机会执行后续的完成打印。
如果你将
gather调用改为await asyncio.gather(*[sleep_and_print(i) for i in range(3)]),main会等待gather的所有任务执行完毕才返回,1秒的等待时间足够所有6个任务执行完成,不会再抛出取消异常。
问题2:仅 await 第二个任务时两个任务都能执行完成的原因
await asyncio.create_task(sleep_and_print(1))会阻塞当前的main协程,直到第二个任务完全执行完毕才会继续向下执行,整个阻塞时长为1秒。- 这1秒的等待窗口内,事件循环是正常运行的,此前创建的第一个任务
asyncio.create_task(sleep_and_print(0))会被正常调度,sleep(1)结束后就会执行完成打印,和第二个任务几乎同时执行完毕,所以两个任务都能跑完。 - 对比你最初的代码,
main没有任何等待逻辑,创建完所有任务后立刻返回,事件循环直接关停,所有还在等待sleep结束的任务都被直接取消,因此只有开始执行的日志,没有完成日志。
内容的提问来源于stack exchange,提问作者anjuna47
相关产品推荐
相关产品推荐

