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

使用单个aiohttp ClientSession后HTTP请求变慢,求原因及优化方法

问题

我的Python程序每隔几小时会向多个不同站点发起HTTP请求。一开始不知道aiohttp推荐的做法是创建唯一的ClientSession并在程序生命周期内复用,所以每次请求都新建ClientSession,当时请求响应耗时在0.3-0.5秒之间。

改成复用单个ClientSession后,本以为会更快,结果请求响应耗时变成了0.5-1.5秒,还经常出现超过1秒的情况,这在之前从未发生过。

为什么这种推荐的方式反而更慢?

我不想改回原来的写法,现在的代码更简洁,而且同一次提交里的其他调整(确定不影响响应时间)也已经完成。有没有办法既能用共享的单个ClientSession,又能保持之前的请求速度?

修改前代码

async def my_func1():
    async with aiohttp.ClientSession() as session:
        async with session.post(...) as resp:
            # 处理响应

async def my_func2():
    async with aiohttp.ClientSession() as session:
        async with session.get(...) as resp:
            # 处理响应

await asyncio.gather(my_func1(), my_func2())

修改后代码

async def my_func1(session: ClientSession):
    async with session.post(...) as resp:
        # 处理响应
        

async def my_func2(session: ClientSession):
    async with session.get(...) as resp:
        # 处理响应

async with aiohttp.ClientSession() as session:
    await asyncio.gather(my_func1(session), my_func2(session))

解答

为什么复用ClientSession反而变慢?

核心原因是连接池的限制和连接复用特性:

  • 修改前每次请求新建ClientSession,相当于每个请求都有独立的连接池(默认每个ClientSession的连接池大小为100),多个请求可以同时向不同站点建立新连接,不会互相阻塞。
  • 修改后复用单个ClientSession,所有请求共享同一个连接池。aiohttp默认限制每个主机最多10个连接,当你请求多个不同站点时,若并发请求数超过连接池的配置限制,后续请求会排队等待可用连接,直接导致耗时增加。
  • 此外,复用闲置连接时可能需要重新握手,但这种情况对耗时的影响远小于连接池排队的问题。

保持复用ClientSession同时提升速度的办法

  1. 调整连接池参数
    创建ClientSession时,通过TCPConnector自定义连接池配置,比如增大单主机的最大连接数或总连接池大小:

    from aiohttp import TCPConnector
    
    # 增大单主机允许的最大连接数(默认10)
    connector = TCPConnector(limit_per_host=50)
    async with aiohttp.ClientSession(connector=connector) as session:
        await asyncio.gather(my_func1(session), my_func2(session))
    

    如果请求的主机数量极多,还可以调整总连接池大小(默认100):

    connector = TCPConnector(limit=200, limit_per_host=50)
    
  2. 临时排查验证(不推荐长期使用)
    若想确认是否是连接复用导致的问题,可临时禁用连接复用,对比耗时变化:

    connector = TCPConnector(force_close=True)
    async with aiohttp.ClientSession(connector=connector) as session:
        # 执行请求逻辑
    

    注意:禁用连接复用会失去其原本的性能优势,仅用于排查问题。

  3. 优化请求并发控制
    如果程序发起的请求量极大,除了调整连接池参数,还可以用asyncio.Semaphore限制并发请求数,避免连接池被占满:

    semaphore = asyncio.Semaphore(50)  # 限制同时并发50个请求
    
    async def my_func1(session: ClientSession):
        async with semaphore:
            async with session.post(...) as resp:
                # 处理响应
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:35:25