requests.get()必须显式设置timeout,推荐拆分为连接超时和读取超时(如(3,10)),并配合retry机制处理临时错误,同时注意系统级tcp参数对实际超时的影响。

requests.get() 的 timeout 参数到底该设多少
超时不是保险丝,设太大反而会让程序卡死更久。默认不设 timeout 就是无限等待,遇到网络挂起或服务无响应,整个线程就僵在那儿了。
实操建议:必须显式传入 timeout,且拆成连接超时和读取超时两部分:
-
timeout=(3, 10)表示连接最多等 3 秒,连上后读响应最多等 10 秒 - 纯数字如
timeout=10是历史兼容写法,等价于(10, 10),但掩盖了连接/读取阶段的差异 - 连接超时(第一个数)通常 2–5 秒足够;读取超时(第二个数)取决于接口实际响应时间,建议比 P95 响应时间高 20%~50%
requests 超时后不会自动重试,得自己兜底
很多人以为设了 timeout 就等于“失败自动再试一次”,其实不是。requests.get() 超时抛出的是 requests.exceptions.Timeout,它不重试,也不触发重定向逻辑。
常见错误现象:请求偶尔超时,日志里只看到一次失败,但业务上需要更高可用性。
立即学习“Python免费学习笔记(深入)”;
实操建议:用 urllib3.util.retry.Retry 配合 requests.adapters.HTTPAdapter 控制重试行为:
- 别直接用
try/except包一层就循环重试——可能把幂等性搞砸(比如重复扣款) - 对 GET 请求可开重试,POST/PUT 建议谨慎;重试次数建议 ≤3,间隔用指数退避(
backoff_factor=0.3) - 务必排除
status_forcelist=(429, 502, 503, 504)等临时错误码,别把 400 错误也重试
异步场景下 aiohttp 的 timeout 更容易被忽略
用 aiohttp.ClientSession 时,timeout 不是传给 get() 的参数,而是要提前配在 session 或 request 级别,漏掉就退化成无限等待。
使用场景:爬虫、网关聚合、定时同步任务——这些地方一旦某个请求卡住,整个协程池可能被拖慢。
实操建议:
- 创建 session 时用
aiohttp.ClientTimeout(total=30, connect=5, sock_read=10)显式控制各阶段 - 单次请求可覆盖:
session.get(url, timeout=aiohttp.ClientTimeout(sock_read=8)) - 注意
total是总时限,会覆盖其他单项;若设了total=5又设connect=10,实际仍按 5 秒截断
超时值受系统级 socket 设置影响
Python 层设了 timeout=3,但底层 TCP 握手可能被操作系统拖得更久——比如 Linux 的 tcp_syn_retries 默认重试 6 次,每次间隔翻倍,加起来能到 20 多秒。
性能影响:线上服务若大量出现“明明设了 3 秒超时,却卡了 20 秒才报错”,大概率是这个原因。
实操建议:
- 检查
/proc/sys/net/ipv4/tcp_syn_retries,生产环境建议调成3(对应约 3 秒) - Docker 容器内需在启动时用
--sysctl注入,或在 entrypoint 里 echo 修改 - 云函数(如 AWS Lambda)无法改内核参数,那就只能靠更保守的 Python 层 timeout + 主动 cancel task
超时不是填个数字就完事,它是连接层、协议层、应用层三者共同作用的结果。最容易被忽略的是:你设的那个数字,未必真能生效。










