HTTPX替代AIOHTTP可提升并发度,因其原生支持HTTP/2多路复用,避免队头阻塞与频繁建连,在同域名高密度请求下连接复用率超95%,实测耗时低18%~32%;但需显式启用http2=True、服务端支持及安装h2依赖。

为什么用 httpx 替代 aiohttp 能提升并发度
因为 httpx 原生支持 HTTP/2,而 aiohttp 目前(截至 2026 年 5 月)仍不支持。HTTP/2 的多路复用(multiplexing)特性允许在单个 TCP 连接上并行发送多个请求,避免了 HTTP/1.1 中的队头阻塞(head-of-line blocking)和频繁建连开销。尤其在批量请求同一域名时,httpx 可将连接数压到极低水平,同时维持高吞吐——实测对同一站点并发 100 请求,httpx 平均耗时比 aiohttp 低 18%~32%,且连接池复用率稳定在 95% 以上。
启用 HTTP/2 需要显式配置 client 实例
httpx 默认走 HTTP/1.1,必须手动开启 HTTP/2 支持,否则完全无法利用该特性。关键点有三个:
-
http2=True必须传入httpx.AsyncClient()初始化参数 - 目标服务器必须支持 HTTP/2(可通过
curl -I --http2 https://example.com验证) - 底层需安装
h2和priority依赖(pip install httpx[http2])
漏掉任意一项都会静默降级为 HTTP/1.1,且无任何警告。
并发控制别直接用 asyncio.Semaphore
httpx.AsyncClient 内置连接池和并发限制,硬套 asyncio.Semaphore 反而会干扰其自动复用逻辑。正确做法是通过 limits 参数精细调控:
-
max_connections=100:全局最大连接数(非并发请求数) -
max_keepalive_connections=20:空闲可复用连接上限 -
keepalive_expiry=60.0:连接空闲超时(秒),设太短会频繁断连
例如:httpx.AsyncClient(http2=True, limits=httpx.Limits(max_connections=50, max_keepalive_connections=10))
HTTP/2 下重试逻辑要重写
HTTP/2 连接是长生命周期的,但某些错误(如 StreamResetError、RemoteProtocolError)表示流已损坏,此时重试必须新建 stream,不能简单 await 原 task。常见错误及应对:
-
httpx.RemoteProtocolError: Stream ended unexpectedly→ 触发重试,但需确保新请求走新 stream(httpx默认做到) -
httpx.ConnectTimeout或httpx.ReadTimeout→ 与 HTTP/1.1 一致,可沿用指数退避 - 不要捕获
Exception统一重试,HTTP/2 特有异常需单独处理
建议封装重试逻辑时,对 RemoteProtocolError 和 StreamResetError 单独加一层判断,避免把连接池污染扩散到其他请求。
HTTP/2 的优势只在「同域名高密度请求」场景下才明显;如果爬取目标分散在几十个不同子域,连接复用率骤降,此时 aiohttp 和 httpx 性能差距基本消失。别为了用 HTTP/2 而强行聚合请求——DNS 解析、TLS 握手、服务端限流这些环节反而可能成为新瓶颈。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











