Python 3 urllib Vs 请求性能
Python 3 urllib Vs requests performance
我正在使用 python 3.5,我正在检查 urllib 模块与请求模块的性能。
我在 python 中写了两个客户端,第一个使用 urllib 模块,第二个使用请求模块。
它们都生成二进制数据,我将其发送到基于烧瓶的服务器,我还从烧瓶服务器 return 向客户端发送二进制数据。
我发现两个模块(urllib,请求)将数据从客户端发送到服务器所花费的时间相同,但是从服务器到客户端的 return 数据所花费的时间快两倍urllib 与请求进行比较。
我正在本地主机上工作。
我的问题是为什么?
我在请求模块上做错了什么使它变慢了?
这是服务器代码:
from flask import Flask, request
app = Flask(__name__)
from timeit import default_timer as timer
import os
@app.route('/onStringSend', methods=['GET', 'POST'])
def onStringSend():
return data
if __name__ == '__main__':
data_size = int(1e7)
data = os.urandom(data_size)
app.run(host="0.0.0.0", port=8080)
这是基于urllib的客户端代码:
import urllib.request as urllib2
import urllib.parse
from timeit import default_timer as timer
import os
data_size = int(1e7)
num_of_runs = 20
url = 'http://127.0.0.1:8080/onStringSend'
def send_binary_data():
data = os.urandom(data_size)
headers = {'User-Agent': 'Mozilla/5.0 (compatible; Chrome/22.0.1229.94; Windows NT)', 'Content-Length': '%d' % len(data), 'Content-Type': 'application/octet-stream'}
req = urllib2.Request(url, data, headers)
round_trip_time_msec = [0] * num_of_runs
for i in range(0,num_of_runs):
t1 = timer()
resp = urllib.request.urlopen(req)
response_data = resp.read()
t2 = timer()
round_trip_time_msec[i] = (t2 - t1) * 1000
t_max = max(round_trip_time_msec)
t_min = min(round_trip_time_msec)
t_average = sum(round_trip_time_msec)/len(round_trip_time_msec)
print('max round trip time [msec]: ', t_max)
print('min round trip time [msec]: ', t_min)
print('average round trip time [msec]: ', t_average)
send_binary_data()
这是基于请求的客户端代码:
import requests
import os
from timeit import default_timer as timer
url = 'http://127.0.0.1:8080/onStringSend'
data_size = int(1e7)
num_of_runs = 20
def send_binary_data():
data = os.urandom(data_size)
s = requests.Session()
s.headers['User-Agent'] = 'Mozilla/5.0 (compatible; Chrome/22.0.1229.94;Windows NT)'
s.headers['Content-Type'] = 'application/octet-stream'
s.headers['Content-Length'] = '%d' % len(data)
round_trip_time_msec = [0] * num_of_runs
for i in range(0,num_of_runs):
t1 = timer()
response_data = s.post(url=url, data=data, stream=False, verify=False)
t2 = timer()
round_trip_time_msec[i] = (t2 - t1) * 1000
t_max = max(round_trip_time_msec)
t_min = min(round_trip_time_msec)
t_average = sum(round_trip_time_msec)/len(round_trip_time_msec)
print('max round trip time [msec]: ', t_max)
print('min round trip time [msec]: ', t_min)
print('average round trip time [msec]: ', t_average)
send_binary_data()
非常感谢
首先,为了重现该问题,我必须将以下行添加到您的 onStringSend
函数中:
request.get_data()
否则,我会收到“连接被对等重置”错误,因为服务器的接收缓冲区一直在填满。
现在,这个问题的直接原因是 Response.content
(在 stream=False
时隐式调用)iterates over the response data in chunks of 10240 bytes:
self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
因此,解决问题最简单的方法是使用stream=True
,从而告诉Requests您将按照自己的节奏读取数据:
response_data = s.post(url=url, data=data, stream=True, verify=False).raw.read()
经过这次改动,Requests 版本的性能与 urllib 版本的性能大致相同。
另请参阅请求文档中的“Raw Response Content”部分以获得有用的建议。
现在,有趣的问题仍然存在:为什么 Response.content
以如此小的块进行迭代?在 talking to Cory Benfield, a core developer of Requests, it looks like there may be no particular reason. I filed issue #3186 中请求进一步调查之后。
我正在使用 python 3.5,我正在检查 urllib 模块与请求模块的性能。
我在 python 中写了两个客户端,第一个使用 urllib 模块,第二个使用请求模块。
它们都生成二进制数据,我将其发送到基于烧瓶的服务器,我还从烧瓶服务器 return 向客户端发送二进制数据。
我发现两个模块(urllib,请求)将数据从客户端发送到服务器所花费的时间相同,但是从服务器到客户端的 return 数据所花费的时间快两倍urllib 与请求进行比较。
我正在本地主机上工作。
我的问题是为什么?
我在请求模块上做错了什么使它变慢了?
这是服务器代码:
from flask import Flask, request
app = Flask(__name__)
from timeit import default_timer as timer
import os
@app.route('/onStringSend', methods=['GET', 'POST'])
def onStringSend():
return data
if __name__ == '__main__':
data_size = int(1e7)
data = os.urandom(data_size)
app.run(host="0.0.0.0", port=8080)
这是基于urllib的客户端代码:
import urllib.request as urllib2
import urllib.parse
from timeit import default_timer as timer
import os
data_size = int(1e7)
num_of_runs = 20
url = 'http://127.0.0.1:8080/onStringSend'
def send_binary_data():
data = os.urandom(data_size)
headers = {'User-Agent': 'Mozilla/5.0 (compatible; Chrome/22.0.1229.94; Windows NT)', 'Content-Length': '%d' % len(data), 'Content-Type': 'application/octet-stream'}
req = urllib2.Request(url, data, headers)
round_trip_time_msec = [0] * num_of_runs
for i in range(0,num_of_runs):
t1 = timer()
resp = urllib.request.urlopen(req)
response_data = resp.read()
t2 = timer()
round_trip_time_msec[i] = (t2 - t1) * 1000
t_max = max(round_trip_time_msec)
t_min = min(round_trip_time_msec)
t_average = sum(round_trip_time_msec)/len(round_trip_time_msec)
print('max round trip time [msec]: ', t_max)
print('min round trip time [msec]: ', t_min)
print('average round trip time [msec]: ', t_average)
send_binary_data()
这是基于请求的客户端代码:
import requests
import os
from timeit import default_timer as timer
url = 'http://127.0.0.1:8080/onStringSend'
data_size = int(1e7)
num_of_runs = 20
def send_binary_data():
data = os.urandom(data_size)
s = requests.Session()
s.headers['User-Agent'] = 'Mozilla/5.0 (compatible; Chrome/22.0.1229.94;Windows NT)'
s.headers['Content-Type'] = 'application/octet-stream'
s.headers['Content-Length'] = '%d' % len(data)
round_trip_time_msec = [0] * num_of_runs
for i in range(0,num_of_runs):
t1 = timer()
response_data = s.post(url=url, data=data, stream=False, verify=False)
t2 = timer()
round_trip_time_msec[i] = (t2 - t1) * 1000
t_max = max(round_trip_time_msec)
t_min = min(round_trip_time_msec)
t_average = sum(round_trip_time_msec)/len(round_trip_time_msec)
print('max round trip time [msec]: ', t_max)
print('min round trip time [msec]: ', t_min)
print('average round trip time [msec]: ', t_average)
send_binary_data()
非常感谢
首先,为了重现该问题,我必须将以下行添加到您的 onStringSend
函数中:
request.get_data()
否则,我会收到“连接被对等重置”错误,因为服务器的接收缓冲区一直在填满。
现在,这个问题的直接原因是 Response.content
(在 stream=False
时隐式调用)iterates over the response data in chunks of 10240 bytes:
self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
因此,解决问题最简单的方法是使用stream=True
,从而告诉Requests您将按照自己的节奏读取数据:
response_data = s.post(url=url, data=data, stream=True, verify=False).raw.read()
经过这次改动,Requests 版本的性能与 urllib 版本的性能大致相同。
另请参阅请求文档中的“Raw Response Content”部分以获得有用的建议。
现在,有趣的问题仍然存在:为什么 Response.content
以如此小的块进行迭代?在 talking to Cory Benfield, a core developer of Requests, it looks like there may be no particular reason. I filed issue #3186 中请求进一步调查之后。