You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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,但循环却提前终止,核心原因在于任务的取消和完成是异步过程:

  1. task.cancel()仅发送取消请求,不会立刻将任务标记为完成。此时任务仍处于等待asyncio.sleep(5)结束的状态,所以task.done()返回False是符合预期的。
  2. 关键发生在await asyncio.sleep(1)的执行阶段:当main函数暂停在这个sleep时,事件循环会调度其他可运行的任务——也就是被标记为取消的delay任务。此时delay任务中的await asyncio.sleep(5)会响应取消请求,抛出CancelledError。由于delay函数没有捕获这个异常,任务会直接终止,此时task.done()会切换为True。
  3. 当await asyncio.sleep(1)执行完毕,main函数回到循环开头,再次检查not task.done()时,条件已经不满足(任务已终止),因此循环退出,执行后续代码。

另外需要注意:如果去掉注释执行await task,此时会在main函数中触发CancelledError(任务终止时的未处理异常会在await时传播),但不影响任务本身的done状态。

内容的提问来源于stack exchange,提问作者Dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:30:51