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

为何asyncio.sleep会影响任务取消时机及执行状态?

import asyncio

async def cancel_me():
    print('cancel_me(): before sleep')

    try:
        # 等待1小时
        await asyncio.sleep(3600)
    except asyncio.CancelledError:
        print('cancel_me(): cancel sleep')
        raise
    finally:
        print('cancel_me(): after sleep')

async def main():
    # 创建一个"cancel_me"任务
    task = asyncio.create_task(cancel_me())

    # 如果注释掉这行,会直接输出 -> main(): cancel_me is cancelled now
    await asyncio.sleep(1) 
    # 这会安排在下一轮事件循环时,给被包装的协程抛出CancelledError异常
    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        print("main(): cancel_me is cancelled now")

asyncio.run(main())

不同场景下的输出

保留await asyncio.sleep(1)时的输出

cancel_me(): before sleep
cancel_me(): cancel sleep
cancel_me(): after sleep
main(): cancel_me is cancelled now

注释掉await asyncio.sleep(1)时的输出

main(): cancel_me is cancelled now

问题解答

1. 为何仅注释该asyncio.sleep命令会产生上述输出差异?

asyncio.create_task只是把任务调度到事件循环的待执行队列,不会立即执行。如果没有await asyncio.sleep(1),main协程会直接走到task.cancel()——此时cancel_me还没开始执行,取消一个未启动的任务不会触发协程内部的任何逻辑,后续await task直接抛出CancelledError,只会输出main()里的提示。

保留await asyncio.sleep(1)时,main协程挂起1秒,事件循环会趁机执行cancel_me:它先打印before sleep,然后挂起在await asyncio.sleep(3600)上。1秒后main恢复执行并调用task.cancel(),此时CancelledError会被抛进正在挂起的cancel_me协程,触发异常捕获和finally逻辑,所以会输出完整的日志。

2. 是否create_task后的任何await都会启动已创建/调度的任务?

是的。create_task只是把任务加入事件循环队列,事件循环只有在当前协程挂起(遇到await操作)时,才会切换去执行队列里的其他任务。所以只要main里有任何await(不管是sleep、await task还是其他异步操作),已调度的cancel_me任务都会被启动执行。

3. 在将main()中await asyncio.sleep(1)之后的代码注释,替换为await asyncio.sleep(5)且未调用task.cancel()时,cancel_me()中的CancelledError异常仍被触发并打印cancel_me(): cancel sleep,这是为何?

当main执行到await asyncio.sleep(5)时,cancel_me会先启动执行,然后挂起在await asyncio.sleep(3600)上。5秒后main协程执行完毕,asyncio.run()会关闭事件循环,此时所有未完成的任务都会被自动取消——事件循环会给这些任务抛出CancelledError,因此cancel_me里的异常捕获逻辑被触发,打印对应内容后执行finally块。


内容的提问来源于stack exchange,提问作者An old man in the sea.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:55:24