问题描述
我正在尝试创建一个水瓶应用程序,应该:
我做了一个快速测试,并在Flask开发服务器上运行了它,它按照预期工作。被红色的WARNING: This is a development server. Do not use it in a production deployment.所吓倒,我试着把它放在WSGI服务器上,但是服务生和GUnicorn的效果都要慢得多。下面是测试(使用人工输入、微小输出和完全可复制代码的玩具问题)。
运行测试的代码
我把这三个文件放在一个文件夹里:
basic_flask_app.py (这里的代码对获取的数据几乎没有什么作用;我拥有的真正的代码是一个在GPU上运行相当快的深入学习模型,但是这里的示例是为了使问题更加极端)。
import numpy as np
from flask import Flask, request
from do_request import IS_SMALL_DATA, WIDTH, HEIGHT
app = Flask(__name__)
@app.route('/predict', methods=['POST'])
def predict():
numpy_bytes = np.frombuffer(request.data, np.float32)
if IS_SMALL_DATA:
numpy_image = np.zeros((HEIGHT, WIDTH)) + numpy_bytes
else:
numpy_image = numpy_bytes.reshape(HEIGHT, WIDTH)
result = numpy_image.mean(axis=1).std(axis=0)
return result.tobytes()
if __name__ == '__main__':
app.run(host='localhost', port=80, threaded=False, processes=1)编辑:这个问题的原始版本缺少了上面对app.run的调用中的参数app.run,所以下面的GUnicorn和服务生的行为是不一样的,而是被迫采用单线程/进程;我现在已经添加了它,并且重新测试,结果没有改变,在这个更改之后,烧瓶服务器仍然是快速的--如果有更快的话,
do_request.py
import requests
import numpy as np
from tqdm import trange
WIDTH = 2500
HEIGHT = 3000
IS_SMALL_DATA = False
def main(url='http://127.0.0.1:80/predict'):
n = WIDTH * HEIGHT
if IS_SMALL_DATA:
np_image = np.zeros(1, dtype=np.float32)
else:
np_image = np.arange(n).astype(np.float32) / np.float32(n)
results = []
for _ in trange(50):
results.append(requests.post(url, data=np_image.tobytes()))
if __name__ == '__main__':
main()waitress_server.py
from waitress import serve
import basic_flask_app
serve(basic_flask_app.app, host='127.0.0.1', port=80, threads=1)测试结果
在使用以下三个命令之一启动模型之后,我已经运行了运行python do_requests.py的测试:
python basic_flask_app.py
python waitress_server.py
gunicorn -w 1 basic_flask_app:app -b 127.0.0.1:80使用这三个选项,并切换IS_SMALL_DATA标志(如果为True,则只传输4个字节的数据;如果为False,则为30 of ),我得到了以下时间:
50 requests Flask Waitress GUnicorn
30MB input, 4B output: 00:01 (28.6 it/s) 00:11 (4.42 it/s) 00:11 (4.26 it/s)
4B input, 4B output: 00:01 (25.2 it/s) 00:02 (23.6 it/s) 00:01 (26.4 it/s)如您所见,与传输的数据量无关的Flask开发服务器非常快(“小”数据甚至更慢一些,可能是因为它浪费了在50个迭代中分配内存的时间),而服务生和GUnicorn在传输的数据越多,速度就越快。
问题
现在,我有几个问题:
发布于 2021-06-22 08:05:43
这才是真正的。也许这会解释这个问题。
request.data,花费了不同的时间。使用胶角的时间超过95%,为0.35s。当使用烧瓶web应用程序时,这个花费大约是0.001s.werkzeug/wrappers/base_request.py 456 line上rv = self.stream.read()
当使用烧瓶开发服务器。这个self.stream是werkzeug.wsgi.LimitedStream。这条线大约值0.001s。
在使用火鸟的时候。这个self.stream是gunicorn.http.body.Body。这将花费超过0.3s。
gunicorn/http/body.py。第214-218号线而大小> self.buf.tell():data = self.reader.read(1024)如果不是数据:断开self.buf.write(数据)
这花费超过0.3s。
self.buf.write(self.reader.read(size))。这使得它花费了0.07s。--现在= time.time()缓冲区=self.reader.read(大小) print(time.time() - now) now = time.time()
我发现第一线值0.053美元。第二线花费0.017.
我想我已经找到原因了。
首先,使用io.BytesIO将原始字节封装到他的特殊对象中。
第二,使用while循环读取字节,这将花费更多的时间。
我想这些代码的目的是支持高并发性。
在你的例子中,我认为你可以直接使用gevent。
from gevent.pywsgi import WSGIServer
from basic_flask_app import app
http_server = WSGIServer(('', 80), app)
http_server.serve_forever()这要快得多。
https://stackoverflow.com/questions/67938278
复制相似问题