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

使用async with是否无需asyncio.sleep(0)即可优雅关闭aiohttp.ClientSession?

为什么多数开发者仍用async with管理aiohttp.ClientSession?

首先明确:async with的写法(#1)是aiohttp官方推荐的标准用法,文档里的asyncio.sleep(0)建议是针对特定场景,而非每次请求都需要遵循的规则。下面具体拆解原因:

1. async with已经正确处理了Session的生命周期

aiohttp.ClientSession的异步上下文管理器实现中,退出上下文时会自动调用await session.close(),而close()方法内部已经封装了完整的清理逻辑:

  • 等待所有pending的HTTP请求任务完成
  • 正确释放连接池资源
  • 处理内部的回调队列

完全不需要手动添加asyncio.sleep(0),这属于画蛇添足。

2. 文档里的「优雅关闭」是针对全局长连接场景

你看到的「优雅关闭」建议,是给长期运行的全局Session准备的——比如整个Web应用共享一个Session实例,在应用 shutdown 阶段需要关闭它时,可能需要asyncio.sleep(0)让事件循环处理完剩余的异步回调,避免资源泄漏。但这种场景和单次请求创建/销毁Session的场景完全不同。

3. 你的#2代码存在明显问题

  • 逻辑顺序错误:先关闭Session再读取response.json()会直接报错——因为Response的内容依赖Session持有的连接,Session关闭后连接被释放,无法再读取响应体。
  • 冗余的asyncio.sleep(0):在单次请求场景下,这个操作只会增加事件循环的调度开销,没有任何实际作用。
  • 宽泛的异常捕获:except:会捕获所有异常,包括KeyboardInterrupt这类系统信号,不利于调试和错误处理。

正确的写法依然是#1

async def get_url(**kwargs):   
    async with aiohttp.ClientSession() as session:  
        async with session.get(**kwargs) as response:  
            return await response.json()

如果需要复用Session(比如多次请求共享连接池),应该把Session的创建放在请求函数外部,在应用生命周期结束时统一关闭,而不是每次请求都手动创建/销毁:

# 全局或模块级别的Session
session = aiohttp.ClientSession()

async def get_url(**kwargs):   
    async with session.get(**kwargs) as response:  
        return await response.json()

# 应用 shutdown 时执行
async def shutdown():
    await session.close()
    # 仅在特殊情况下需要这一步,比如有未处理的回调
    await asyncio.sleep(0)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 19:22:04