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

向同一主机发送多HTTP GET请求致aiohttp客户端卡顿问题排查

解决aiohttp持久连接下批量下载超时问题

从你的描述和日志来看,问题的核心在于HTTP/1.1持久连接的复用逻辑异常,具体是因为请求完成后没有正确读取完整响应体,导致连接无法被放回连接池,最终引发事件循环阻塞超时。下面是具体的分析和解决方案:

问题根源

  1. 响应体未完整读取:你的download_site函数中,虽然用了async with response,但手动调用response.release()且没有读取响应体内容。在aiohttp的HTTP/1.1持久连接机制中,只有当响应体被完全读取后,连接才会被标记为可用并放回连接池。如果跳过这一步,连接会被一直占用,新请求只能等待空闲连接,最终触发超时。
  2. 连接池状态异常:当大量请求并发时,被占用的连接无法释放,连接池耗尽,事件循环在等待IO事件时出现超时日志poll 14805.463 ms took 14808.587 ms: timeout。而HTTP/1.0没有持久连接,每个请求新建连接,所以不会出现这个问题。

解决方案

1. 修复响应体读取逻辑

修改download_site函数,确保读取完整的响应体,让aiohttp正确释放连接到池里:

async def download_site(session, url):
    # 注意给URL加上http://前缀,避免aiohttp解析错误
    full_url = f"http://{url[0]}"
    async with session.request(
        method="GET", 
        url=full_url, 
        params=url[1], 
        ssl=False, 
        expect100=False
    ) as response:
        # 读取完整响应体,确保连接可以被复用
        await response.read()
        return response.status

移除手动的response.release(),因为async with上下文管理器会自动处理连接的释放逻辑,手动调用反而可能干扰正常流程。

2. 优化TCPConnector参数

调整连接池的配置,添加连接存活时间和自动清理机制,避免空闲连接长期占用资源:

async with aiohttp.ClientSession(
    headers={"Connection": "keep-alive"},
    connector=aiohttp.TCPConnector(
        limit=6,  # 保持你的6个连接限制
        ttl=30,  # 连接最大存活时间(秒)
        cleanup_interval=10,  # 每10秒清理一次空闲连接
        enable_cleanup_closed=True  # 自动清理已关闭的连接
    ),
    raise_for_status=True
) as session:

3. 修正代码中的语法错误

你的代码里存在几处可能导致异常的语法问题,建议一并修复:

  • 导入time模块:import time
  • 修正__name__判断:if __name__ == "__main__":
  • 修正retrieve_file调用的参数:await asyncio.wait_for(retrieve_file(_file, run), timeout=15.0)
  • 确保num_main_obj和list_obj变量已正确定义

验证效果

修改后,Wireshark应该能看到连接被复用(同一TCP连接处理多个请求),同时不会再出现poll timeout日志,批量下载超过20个文件时也能正常完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:26:19