Python 3 urllib VS 请求性能

标签 python performance python-requests urllib2 urllib3

我正在使用 python 3.5,我正在检查 urllib 模块与请求模块的性能。 我用 python 编写了两个客户端,第一个使用 urllib 模块,第二个使用 request 模块。 他们都生成一个二进制数据,我将其发送到基于 flask 的服务器,我也从 flask 服务器返回一个二进制数据给客户端。 我发现将数据从客户端发送到服务器所花费的时间对于两个模块(urllib,请求)来说是相同的,但是从服务器返回数据到客户端所花费的时间在 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 以如此小的 block 进行迭代?在talking to Cory Benfield之后作为 Requests 的核心开发者,看起来可能没有特别的原因。我提交了 issue #3186在请求进一步调查这一点。

关于Python 3 urllib VS 请求性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37135880/

相关文章:

python - celery 4.0.0 : No such transport: django

python - 如何在pandas中没有聚合函数的情况下对列进行分组?

performance - 如何在 MATLAB 中编写矢量化函数

bash - 如何使这个 bash 素数生成器更快 [SPOJ]

python - 机器人框架通过 cookie 获取请求 (RequestsLibrary) - TypeError

python - 如何找到正确的 xpath 并循环遍历表?

python - 使用枕头的图像处理代码有问题吗?

javascript - 在 javascript 中,访问 'window.Math' 比访问没有 'Math' 的 'window.' 对象慢还是快?

python - 程序将我发送到错误功能,如何将其更改为ItayVAT?

python - Django ListView 中当前用户对象的列表