使用单个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同时提升速度的办法
调整连接池参数
创建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)临时排查验证(不推荐长期使用)
若想确认是否是连接复用导致的问题,可临时禁用连接复用,对比耗时变化:connector = TCPConnector(force_close=True) async with aiohttp.ClientSession(connector=connector) as session: # 执行请求逻辑注意:禁用连接复用会失去其原本的性能优势,仅用于排查问题。
优化请求并发控制
如果程序发起的请求量极大,除了调整连接池参数,还可以用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
相关产品推荐
相关产品推荐

