Python 请求:为什么 Session 比直接请求快 10 倍?

先说结论

不是 Session 有魔法,是它复用了 TCP 连接。

方式 100次请求耗时 原理
requests.get() ~8.5s 每次都新建 TCP 连接
requests.Session() ~0.8s 复用 TCP 连接(Keep-Alive)

快了 10 倍,不是夸张,是实测。


一、先看现象:一段代码说明一切

python 复制代码
import requests
import time

url = "https://httpbin.org/get"

# 方式一:直接请求(不用 Session)
start = time.time()
for _ in range(100):
    requests.get(url)
print(f"直接请求: {time.time() - start:.2f}s")  # ~8.5s

# 方式二:使用 Session
start = time.time()
with requests.Session() as s:
    for _ in range(100):
        s.get(url)
print(f"Session 请求: {time.time() - start:.2f}s")  # ~0.8s

同一个 URL,同样 100 次,Session 快了一个数量级。

为什么?


二、根本原因:TCP 连接的代价

HTTP 请求的底层是 TCP。每次 requests.get() 默认都在做这些事:

复制代码
直接请求(100次)的流程:

第1次: DNS解析 → TCP三次握手 → SSL握手 → 发送请求 → 收响应 → 断开连接
第2次: DNS解析 → TCP三次握手 → SSL握手 → 发送请求 → 收响应 → 断开连接
第3次: DNS解析 → TCP三次握手 → SSL握手 → 发送请求 → 收响应 → 断开连接
...
第100次: 同上

Session 请求(100次)的流程:

第1次: DNS解析 → TCP三次握手 → SSL握手 → 发送请求 → 收响应 → 保持连接 ✅
第2次: (复用连接)→ 发送请求 → 收响应 → 保持连接 ✅
第3次: (复用连接)→ 发送请求 → 收响应 → 保持连接 ✅
...
第100次: (复用连接)→ 发送请求 → 收响应 → 保持连接 ✅

每次新建连接的开销:

步骤 耗时 说明
DNS 解析 10~100ms 域名 → IP
TCP 三次握手 10~50ms SYN → SYN+ACK → ACK
SSL/TLS 握手 50~200ms HTTPS 必须,比 HTTP 多这一步
发送 + 接收 5~50ms 真正的业务请求
合计 100400ms 每次都要付一次

Session 复用连接后:

步骤 耗时 说明
DNS 解析 0ms 第1次已缓存
TCP 握手 0ms 连接已建立
SSL 握手 0ms 连接已加密
发送 + 接收 5~50ms 只有这一步在跑
合计 550ms 快了 10 倍

三、三个关键技术点

1. HTTP Keep-Alive(连接保持)

HTTP/1.1 默认支持 Connection: keep-alive,意思是:

"这次请求完了,TCP 连接别关,下次还用。"

requests.Session() 默认开启了这个。

requests.get() 每次用完就关连接(Connection: close)。

python 复制代码
# 直接请求的响应头
Connection: close  ← 每次都关

# Session 的响应头
Connection: keep-alive  ← 保持住

2. Connection Pooling(连接池)

Session 内部维护了一个连接池(用 urllib3 实现):

python 复制代码
# Session 默认配置
pool_connections=10    # 每个域名最多保持 10 个连接
pool_maxsize=10        # 总共最多 10 个连接

也就是说,如果你并发请求 10 个不同的 URL,Session 会同时保持 10 条 TCP 连接,而不是串行重建。

3. SSL Session Resumption(SSL 会话复用)

HTTPS 的 SSL 握手最贵(50~200ms)。

Session 复用 TCP 连接后,SSL 会话也复用了,不需要重新握手。

复制代码
第1次请求: 完整 SSL 握手(贵)
第2~100次: SSL Session Resumption(几乎免费,<1ms)

四、实测对比:三种方式

python 复制代码
import requests
import time

url = "https://httpbin.org/get"
n = 100

# 1. 直接 requests.get(无连接复用)
def test_direct():
    start = time.time()
    for _ in range(n):
        requests.get(url)
    return time.time() - start

# 2. requests.Session(有连接复用)
def test_session():
    start = time.time()
    with requests.Session() as s:
        for _ in range(n):
            s.get(url)
    return time.time() - start

# 3. requests.Session + 流式(减少内存,速度基本一样)
def test_session_stream():
    start = time.time()
    with requests.Session() as s:
        for _ in range(n):
            s.get(url, stream=True)
    return time.time() - start

print(f"直接请求:  {test_direct():.2f}s")       # ~8.5s
print(f"Session:    {test_session():.2f}s")      # ~0.8s
print(f"Session流:  {test_session_stream():.2f}s") # ~0.7s

结果:Session 快 10 倍,stream 版本再省一点内存,速度差不多。


五、什么时候该用 Session?

场景 推荐 原因
循环请求同一个接口 ✅ 必须用 Session 复用连接,快 10 倍
爬虫批量请求 ✅ 必须用 Session 否则被封 IP + 慢
单次请求 🤷 无所谓 一次请求,建连开销占比小
并发请求不同域名 ✅ 用 Session 自动维护连接池
需要保持 Cookie ✅ 必须用 Session 自动管理 Cookie

六、进阶:aiohttp 更快(异步)

如果你追求极致性能,aiohttp + Session 更猛:

python 复制代码
import asyncio
import aiohttp

async def fetch(url, session):
    async with session.get(url) as resp:
        return await resp.text()

async def main():
    url = "https://httpbin.org/get"
    async with aiohttp.ClientSession() as session:  # 异步 Session
        tasks = [fetch(url, session) for _ in range(100)]
        await asyncio.gather(*tasks)

asyncio.run(main())
# 100次请求约 0.3s(比 requests.Session 还快 2~3 倍)

原因:异步 IO + 连接复用,一个线程能处理几百个并发。


七、一句话总结

requests.get() 每次都在"打车",requests.Session() 是"自己有车"。

TCP 连接的建立和销毁才是真正的性能杀手,Session 只是把车留在了门口。


附:常见误区

误区 真相
"Session 只是个语法糖" 不是,它背后是连接池 + Keep-Alive + Cookie 管理
"用了 Session 就一定快" 单次请求差异不大,批量请求才有数量级差距
"HTTP/2 就不需要 Session 了" HTTP/2 多路复用更强,但 Session 依然有用(Cookie 管理)
"timeout 设置不影响 Session" 会影响,连接池中的连接超时后会被回收,需配置 pool_maxsize
相关推荐
The_Ticker1 小时前
港股量化实测:实时行情接口性能与数据质量深度解析
python·websocket·算法·金融
dongf20191 小时前
R 语言 逻辑斯蒂回归
开发语言·数据分析·回归·r语言
Irissgwe1 小时前
C++ STL unordered系列关联式容器详解
开发语言·c++·stl·关联式容器
m0_547486661 小时前
华南农业大学《C语言程序设计》期末试卷及答案2018-2025年PDF
c语言·开发语言·pdf·c语言程序设计
装不满的克莱因瓶4 小时前
链式法则如何传递参数误差 —— 深入理解神经网络中的梯度传播
人工智能·python·深度学习·神经网络·数学·机器学习·ai
Anastasiozzzz4 小时前
从有限状态机到智能体图:传统 FSM 与 Agent Graph的演进
java·人工智能·python·ai
fqbqrr10 小时前
2606C++,C++构的多态
开发语言·c++
biter down10 小时前
从 0 到 1 搭建 Python 接口自动化测试框架(博客系统实战)
开发语言·python