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()

实际的连接池逻辑都在 HTTPAdapterurllib3 中。

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”,性能就会被浪费掉。