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

asyncio.wait_for等待Event时aiohttp无法正常清理的原因咨询

问题原因与解决方案:asyncio.wait_for + asyncio.Event导致aiohttp清理流程阻塞

核心问题分析

你遇到的问题本质是asyncio.wait_for与asyncio.Event.wait()的组合在取消时的特殊行为,导致aiohttp的清理流程无法正常调度执行:

  1. Event.wait()的挂起逻辑:当Event未被触发时,wait()会将当前任务加入自身的_waiters列表,然后挂起在一个未完成的内部Future上。
  2. 取消流程的竞态:当调用t.cancel()取消任务时,wait_for会先触发e.wait()协程的取消,此时e.wait()需要执行finally块将任务从_waiters中移除。但这个操作与aiohttp的cleanup协程(执行ctx ending的代码)在事件循环中存在调度竞态——wait_for的取消处理占据了事件循环的调度权,导致cleanup代码无法被执行,最终事件循环直接退出,ctx ending日志无法输出。

而替换为asyncio.sleep(100)时,sleep的取消通过定时器触发,协程能立即响应并退出,事件循环可以顺利调度cleanup流程,所以日志正常输出。

解决方案

方案1:取消任务后等待其完成

修改ctx函数的finally块,在取消任务后等待任务处理完取消逻辑:

finally:
    logging.info("ctx ending")
    t.cancel()
    try:
        await t
    except asyncio.CancelledError:
        # 捕获任务的取消异常,不做额外处理
        pass

这样能确保任务的取消流程完全结束,事件循环可以顺利执行cleanup代码,ctx ending和任务的取消日志都会正常输出。

方案2:使用Event.wait()的原生超时(Python 3.11+)

Python 3.11及以上版本中,asyncio.Event.wait()新增了timeout参数,可以直接替代asyncio.wait_for,避免两者组合带来的问题:

# 替换原wait_for代码
await e.wait(timeout=10000)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:57:02