为何asyncio任务cancel后done()为False,while循环仍终止?
Asyncio任务取消后循环提前终止的原因解析
待分析代码
import asyncio async def delay(sec: int): print(f"delay() going to sleep for {sec}s") await asyncio.sleep(sec) print("delay() waked up") async def main(): task = asyncio.create_task(delay(5)) seconds_elapsed = 0 while not task.done(): print(f"checking task finished... {task.done()}") await asyncio.sleep(1) seconds_elapsed += 1 if seconds_elapsed == 3: print(f"cancelled result: {task.cancel()}") print(f"task is done: {task.done()}") print("main() awaiting task") try: # await task pass except asyncio.CancelledError: print("task was cancelled") print("main() finished") asyncio.run(main())
执行输出日志
checking task finished... False delay() going to sleep for 5s checking task finished... False checking task finished... False cancelled result: True task is done: False checking task finished... False main() awaiting task main() finished
问题解析
调用task.cancel()后task.done()返回False,但循环却提前终止,核心原因在于任务的取消和完成是异步过程:
task.cancel()仅发送取消请求,不会立刻将任务标记为完成。此时任务仍处于等待asyncio.sleep(5)结束的状态,所以task.done()返回False是符合预期的。- 关键发生在
await asyncio.sleep(1)的执行阶段:当main函数暂停在这个sleep时,事件循环会调度其他可运行的任务——也就是被标记为取消的delay任务。此时delay任务中的await asyncio.sleep(5)会响应取消请求,抛出CancelledError。由于delay函数没有捕获这个异常,任务会直接终止,此时task.done()会切换为True。 - 当
await asyncio.sleep(1)执行完毕,main函数回到循环开头,再次检查not task.done()时,条件已经不满足(任务已终止),因此循环退出,执行后续代码。
另外需要注意:如果去掉注释执行await task,此时会在main函数中触发CancelledError(任务终止时的未处理异常会在await时传播),但不影响任务本身的done状态。
内容的提问来源于stack exchange,提问作者Dev
相关产品推荐
相关产品推荐

