Paw*_*ech 8 python http python-requests
我今天正在测试不同的Python HTTP库,我意识到http.client库的运行速度要快得多requests.
要测试它,您可以运行以下两个代码示例.
import http.client
conn = http.client.HTTPConnection("localhost", port=8000)
for i in range(1000):
conn.request("GET", "/")
r1 = conn.getresponse()
body = r1.read()
print(r1.status)
conn.close()
Run Code Online (Sandbox Code Playgroud)
这里是与python-requests做同样事情的代码:
import requests
with requests.Session() as session:
for i in range(1000):
r = session.get("http://localhost:8000")
print(r.status_code)
Run Code Online (Sandbox Code Playgroud)
如果我启动SimpleHTTPServer:
> python -m http.server
Run Code Online (Sandbox Code Playgroud)
并运行上面的代码示例(我正在使用Python 3.5.2).我得到以下结果:
http.client:
0.35user 0.10system 0:00.71elapsed 64%CPU
Run Code Online (Sandbox Code Playgroud)
蟒蛇,请求:
1.76user 0.10system 0:02.17elapsed 85%CPU
Run Code Online (Sandbox Code Playgroud)
我的测量和测试是否正确?你也可以复制它们吗?如果有,是否有人知道内部发生了什么http.client,使它更快?为什么处理时间有这么大的差异?
Paw*_*ech 12
@Lukasa在 python-requests repo 中发布的复制粘贴响应:
Requests 较慢的原因是它比 httplib 做得更多。httplib 可以被认为是堆栈的底层:它进行套接字的低级争用。请求是更上两层,并添加了诸如 cookie、连接池、附加设置和其他各种有趣的东西。这必然会减慢速度。我们只需要比 httplib 计算更多。
您可以通过查看请求的 cProfile 结果来看到这一点:结果比 httplib 多得多。对于高级库来说,这总是意料之中的:它们增加了更多的开销,因为它们必须做更多的工作。
虽然我们可以查看有针对性的性能改进,但在所有情况下调用堆栈的绝对高度都会显着损害我们的性能。这意味着“请求比 httplib 慢”的抱怨总是正确的:这就像抱怨“请求比向套接字发送精心制作的原始字节慢”一样。这是真的,而且永远都是真的:对此我们无能为力。
Jas*_*n S 11
基于两者的分析,主要区别似乎是requests版本正在为每个请求执行DNS查找,而http.client版本只执行一次.
# http.client
ncalls tottime percall cumtime percall filename:lineno(function)
1974 0.541 0.000 0.541 0.000 {method 'recv_into' of '_socket.socket' objects}
1000 0.020 0.000 0.045 0.000 feedparser.py:470(_parse_headers)
13000 0.015 0.000 0.563 0.000 {method 'readline' of '_io.BufferedReader' objects}
...
# requests
ncalls tottime percall cumtime percall filename:lineno(function)
1481 0.827 0.001 0.827 0.001 {method 'recv_into' of '_socket.socket' objects}
1000 0.377 0.000 0.382 0.000 {built-in method _socket.gethostbyname}
1000 0.123 0.000 0.123 0.000 {built-in method _scproxy._get_proxy_settings}
1000 0.111 0.000 0.111 0.000 {built-in method _scproxy._get_proxies}
92000 0.068 0.000 0.284 0.000 _collections_abc.py:675(__iter__)
...
Run Code Online (Sandbox Code Playgroud)
你提供http.client.HTTPConnection()一次主机名,所以它会调用gethostbyname一次.requests.Session可能会缓存主机名查找,但显然不会.
编辑:经过一些进一步的研究,这不仅仅是一个简单的缓存问题.有一个函数可以确定是否绕过最终调用的代理,gethostbyname无论实际请求本身如何.
| 归档时间: |
|
| 查看次数: |
6368 次 |
| 最近记录: |