我今天正在测试不同的 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()
这里是用 python-requests 做同样事情的代码:
import requests
with requests.Session() as session:
for i in range(1000):
r = session.get("http://localhost:8000")
print(r.status_code)
如果我启动 SimpleHTTPServer:
> python -m http.server
并运行上面的代码示例(我使用的是 Python 3.5.2)。我得到以下结果:
http.客户端:
0.35user 0.10system 0:00.71elapsed 64%CPU
python 请求:
1.76user 0.10system 0:02.17elapsed 85%CPU
我的测量和测试是否正确?你也能复制它们吗?如果是,有没有人知道 http.client
内部发生了什么让它变得更快?为什么处理时间会有这么大的差异?
最佳答案
基于对两者的分析,主要区别似乎是 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__)
...
您将主机名提供给 http.client.HTTPConnection()
一次,因此调用一次 gethostbyname
是有意义的。 requests.Session
可能可以缓存主机名查找,但显然不能。
编辑:经过进一步研究,这不仅仅是缓存的简单问题。有一个函数用于确定是否绕过最终调用 gethostbyname
的代理,而不考虑实际请求本身。
关于python - 为什么 Python 3 http.client 比 python-requests 快这么多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39435443/