HTTP 基于 TCP。每次新建连接都要三次握手,频繁请求时开销很大。连接池的价值在于复用连接,降低延迟与 CPU 消耗。
在 Python 里最常见的是 requests,它底层依赖 urllib3 的连接池。
requests.Session
Session 会复用连接,因此性能更好。先看最小示例,再拆内部链路。
import requests
s = requests.Session()
resp = s.get("https://httpbin.org/get")
print(resp.status_code)
核心调用链:get() → request() → send() → adapter.send()。
实际的连接池逻辑都在 HTTPAdapter 与 urllib3 中。
HTTPAdapter 关键参数
HTTPAdapter 决定连接池大小:
pool_connections:缓存多少个连接池(按 host)pool_maxsize:每个连接池最多多少连接pool_block:池满时是否阻塞
import requests
from requests.adapters import HTTPAdapter
s = requests.Session()
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=20, pool_block=True)
s.mount("http://", adapter)
s.mount("https://", adapter)
urllib3.HTTPConnectionPool
每个 host 对应一个连接池。关键参数:
maxsize:该 host 最大连接数block:池满是否阻塞等待
简单示例:
import threading
from urllib3 import HTTPConnectionPool
pool = HTTPConnectionPool("example.com", maxsize=2, block=True)
def http_get():
for _ in range(3):
r = pool.request("GET", "/")
print(
"status=", r.status,
"connections=", pool.num_connections,
"requests=", pool.num_requests,
"thread=", threading.current_thread().name,
)
threads = [threading.Thread(target=http_get, name=f"t{i}") for i in range(1, 4)]
for t in threads:
t.start()
如果 block=False,池满时会创建临时连接,但这些连接不会复用。
PoolManager
当请求多个域名时,需要多个连接池。PoolManager 负责管理这些池。
from urllib3 import PoolManager
http = PoolManager(num_pools=10)
resp = http.request("GET", "https://example.com/")
实战建议
- 高频请求尽量复用
Session - 池大小一般与并发线程数接近
- 协程场景要关注连接池过小导致阻塞
小结
连接池的本质是:减少握手、复用 TCP。只要你在高频请求场景里还在“每次 new”,性能就会被浪费掉。