requests 的 pool_maxsize 经常被误解成“最大并发”。这篇用 30 个线程共用一个 Session,看服务器同时接了多少条连接、连接池里到底留住了多少,以及 pool_maxsize、pool_block、pool_connections 各管什么。
默认适配器:pool_connections=10 pool_maxsize=10 pool_block=False 第 1 波(30 个并发请求):耗时 220 ms;服务器同时在处理的请求峰值 30;累计接受 30 条连接 urllib3 的 "Connection pool is full" 警告 20 条;第一条原文:Connection pool is full, discarding connection: 127.0.0.1. Connection pool size: 10
默认的 HTTPAdapter 是 pool_connections=10、pool_maxsize=10、pool_block=False。池里没有空闲连接时,urllib3 照样新建一条;用完后如果池里已经有 10 条,就把多出来的连接关掉并记一条 WARNING:Connection pool is full, discarding connection。所以 30 个线程能同时跑出 30 条连接。
默认 pool_maxsize=10:第 1 波累计 30 条连接(222 ms,警告 20 条);第 2 波累计 50 条连接,新增 20 条(217 ms,累计警告 40 条) pool_maxsize=30:第 1 波累计 30 条连接(218 ms,警告 0 条);第 2 波累计 30 条连接,新增 0 条(213 ms,累计警告 0 条)
多出来的连接不是免费的。第二波 30 个并发来的时候,池里只剩 10 条,另外 20 条要重新建。把 pool_maxsize 调到不小于线程数,第二波就能全部复用。日志里反复出现“pool is full”警告,就是在提示这件事。
pool_maxsize=10, pool_block=True,30 个并发:耗时 623 ms;服务器同时处理的峰值 10;累计 10 条连接;警告 0 条 对照:30 个请求每个 200 ms,如果最多只能 10 个并发,理论下限是 3 批 × 200 = 600 ms 对照 pool_maxsize=30:耗时 233 ms;服务器同时处理的峰值 30;累计 30 条连接
想让池真的限制并发,要设 pool_block=True:池里没有可用连接时线程等待,服务器的并发峰值就被压到 pool_maxsize。实测 30 个请求花了 623 ms,比 3 批 × 200 ms 的理论下限只多 23 ms。代价是线程会被卡住(这里没有配合超时测试等待连接会不会超时)。
pool_connections=1:3 个服务器上累计连接数 [4, 4, 4](共 12 次请求,每个主机 4 次) pool_connections=3:3 个服务器上累计连接数 [1, 1, 1](共 12 次请求,每个主机 4 次)
pool_connections 是 PoolManager 缓存的主机池个数。只留 1 个时,在多个主机间交替请求,每次都新建连接;留 3 个就每个主机复用 1 条。抓很多个域名的爬虫要注意这个值——我只测了“交替访问 3 个主机”这一种模式,没有测更多主机时的淘汰顺序。