Python requests模块因大量内部函数调用运行缓慢,求原因排查
Requests模块本地请求异常缓慢的排查分析
在一台机器上,Python的requests模块发起本地HTTP请求时运行极慢,性能分析显示存在大量内部函数调用;而相同版本的Python、requests在另一台机器上运行正常,urllib3及curl等工具也无异常。
测试数据对比
异常机器上的测试结果
>>> import sys, cProfile, requests, urllib3 >>> sys.version '3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]' >>> requests.__version__ '2.28.1' # 最新2.29.0版本也存在相同问题 >>> cProfile.run('requests.get("http://127.0.0.1:8080")', sort='ncalls') 11717750 function calls (11717748 primitive calls) in 10.091 seconds Ordered by: call count ncalls tottime percall cumtime percall filename:lineno(function) 5220221 0.770 0.000 0.775 0.000 {method 'read' of '_io.TextIOWrapper' objects} 5220221 0.801 0.000 0.801 0.000 shlex.py:68(punctuation_chars) 468483 0.364 0.000 9.564 0.000 shlex.py:101(get_token) 401557 7.612 0.000 9.188 0.000 shlex.py:133(read_token) 200797 0.059 0.000 0.059 0.000 {method 'startswith' of 'str' objects} 66931 0.012 0.000 0.012 0.000 {method 'popleft' of 'collections.deque' objects} 66926 0.012 0.000 0.012 0.000 {method 'appendleft' of 'collections.deque' objects} 66926 0.049 0.000 0.061 0.000 shlex.py:72(push_token) [..] # 剩余调用次数明显更少 >>> cProfile.run('http=urllib3.PoolManager(); http.request("GET", "http://127.0.0.1:8080")', sort='ncalls') 784 function calls (783 primitive calls) in 0.005 seconds
正常机器上的测试结果
>>> cProfile.run('requests.get("http://127.0.0.1:8080")', sort='ncalls') 2432 function calls (2396 primitive calls) in 0.005 seconds
补充测试信息
- 测试使用
python3 -m http.server 8080 --bind 127.0.0.1,更换其他HTTP服务器结果一致; - 通过tcpdump查看网络流量,大部分耗时在TCP连接建立之前;
- urllib3及curl等工具运行正常;
- 虽测试用IPv4地址,但禁用requests的IPv6无效果;
- 已在干净虚拟环境中测试。
可能的原因分析
从性能分析结果看,异常核心在于shlex模块的函数调用次数呈数量级暴涨,结合requests的工作逻辑,可能的原因包括:
- 异常的环境变量配置:requests会读取
HTTP_PROXY、HTTPS_PROXY等环境变量并通过shlex解析,如果这些变量包含超长字符串、语法错误(比如未闭合的引号),会导致shlex进入反复解析的循环,触发百万级调用。 - Python标准库shlex的本地修改:如果该机器上的
shlex.py被自定义补丁修改过(比如篡改了punctuation_chars或read_token的逻辑),会导致字符串解析逻辑异常,产生大量无效调用。 - requests配置文件格式错误:检查用户级或系统级的requests配置文件(如
~/.config/requests/config.ini),若其中代理等配置项存在格式错误,会导致shlex反复解析失败并重试。 - 本地化/编码设置冲突:机器的本地化编码配置异常,导致shlex在处理字符串时出现编码转换的循环操作,触发大量函数调用。
内容的提问来源于stack exchange,提问作者timss
相关产品推荐
相关产品推荐

