为何Python requests.get()访问不可达远程URL超时慢?如何提速?
问题解答
一、远程URL请求超时慢的原因
- 网络路径差异:请求本地主机时,操作系统网络栈直接返回ICMP不可达报文,瞬间判定连接失败;而请求远程主机时,数据包需经过多个路由节点,部分节点可能不返回错误报文,或网络延迟拉长了TCP连接的重试周期。
- TCP默认重试机制:操作系统默认会对未收到SYN-ACK的TCP连接进行多次重试(比如Linux默认重试5次,间隔从1秒指数增长到32秒),requests底层依赖的urllib3会等待操作系统完成整个重试周期才抛出超时错误,这个过程通常耗时几十秒。
- DNS解析延迟:远程URL的域名解析慢,或解析失败时的重试逻辑,会额外增加等待时间。
- requests默认无超时设置:
requests.get()默认timeout参数为None,意味着会一直等待直到操作系统层面的连接超时,而本地场景下操作系统的超时判断远快于远程。
二、让远程请求更快超时的解决方法
- 显式设置timeout参数:这是最直接有效的方式,可设置单个值(总超时时间),或元组(分别指定连接超时和读取超时)。示例:
连接超时控制TCP建立连接的时间,读取超时控制等待响应数据的时间,两者结合能快速终止无效远程请求。# 连接超时3秒,读取超时5秒 response = requests.get("https://example.invalid", timeout=(3, 5)) - 禁用HTTP重试机制:requests默认会自动重试失败连接,通过配置HTTPAdapter关闭重试,避免额外等待:
import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() # 关闭连接、读取、重定向的重试 retry_strategy = Retry(connect=0, read=0, redirect=0) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("http://", adapter) session.mount("https://", adapter) # 配合timeout使用 response = session.get("https://example.invalid", timeout=(3, 5)) - 提前处理DNS解析:手动做DNS解析并设置超时,避免域名解析环节的延迟:
import socket import requests def fast_get(url, dns_timeout=2, connect_timeout=3, read_timeout=5): # 提取域名 hostname = url.split("://")[1].split("/")[0] try: # 设置DNS解析超时 ip = socket.gethostbyname(hostname) except socket.gaierror: raise ValueError("域名解析失败") # 替换域名IP发起请求 ip_url = url.replace(hostname, ip) return requests.get(ip_url, timeout=(connect_timeout, read_timeout)) - 系统层面调整TCP重试参数(谨慎使用):Linux系统可修改
/proc/sys/net/ipv4/tcp_syn_retries减少TCP连接重试次数,比如设置为2:
注意:该修改会影响整个系统的TCP连接行为,生产环境不建议随意调整。echo 2 > /proc/sys/net/ipv4/tcp_syn_retries
内容的提问来源于stack exchange,提问作者Jude Maranga
相关产品推荐
相关产品推荐

