Python使用requests模块如何保持HTTP连接常开以降低请求开销
关于请求开销的问题
你当前直接调用requests.post顶层方法的写法,确实每次都会创建新的TCP连接,产生额外开销:单次TCP连接需要1.5RTT的三次握手开销,如果是HTTPS请求还要额外加上1~2RTT的TLS握手开销,请求量较大的场景下这部分开销占比会非常高。
连接复用的实现方案
requests本身支持HTTP长连接复用,不需要你手动管理套接字,直接使用内置的Session类即可:Session内部维护了urllib3的连接池,只要目标服务器支持HTTP keep-alive(绝大多数公共服务默认都支持),同一个Session对同一域名发起的多次请求会自动复用已建立的连接,无需每次重新建连。
基础用法示例:
import requests # 初始化Session实例,全局维护连接池 session = requests.Session() # 可提前配置通用请求头、超时等参数,无需每次请求重复传 session.headers.update({"User-Agent": "my-app/1.0"}) # 第一次请求会新建连接 response1 = session.post(URL, json={'a': '123', 'b': '456'}) # 后续同域名请求自动复用连接,无建连开销 response2 = session.post(URL, json={'c': '789', 'd': '012'}) # 用完关闭Session释放连接 session.close()
多线程场景的使用说明
你提到的「主线程提前建连、传递套接字给子线程」的思路不推荐:requests的Session不是线程安全的,跨线程共享同一个Session实例会出现请求状态混乱、读写异常的问题;手动传递套接字更会带来状态同步的额外问题,反而会降低稳定性。
正确的实现方案是每个子线程单独创建自己的Session实例:你可以在子线程初始化时先发起一次轻量请求(比如HEAD/OPTIONS请求)提前建连,后续业务请求直接复用该连接,性能和你设想的方案一致,实现更简单稳定。
多线程场景示例:
import threading import requests def thread_worker(url, task_list): # 每个线程独立维护Session,避免线程安全问题 session = requests.Session() # 可选:提前发起轻量请求完成建连,后续业务请求无建连开销 session.head(url, timeout=2) # 执行批量请求 for req_data in task_list: resp = session.post(url, json=req_data) # 处理响应逻辑 print(resp.status_code) session.close() # 启动多线程执行任务 t1 = threading.Thread(target=thread_worker, args=(YOUR_URL, [{"k1":"v1"}, {"k2":"v2"}])) t2 = threading.Thread(target=thread_worker, args=(YOUR_URL, [{"k3":"v3"}, {"k4":"v4"}])) t1.start() t2.start() t1.join() t2.join()
如果需要进一步调整连接池参数,可以自定义HTTPAdapter挂载到Session上:
from requests.adapters import HTTPAdapter session = requests.Session() # 配置HTTP/HTTPS连接池最大连接数、重试次数 adapter = HTTPAdapter(pool_connections=10, pool_maxsize=10, max_retries=2) session.mount("http://", adapter) session.mount("https://", adapter)
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

