问题描述
我正在尝试创建一个 Flask 应用程序,它应该:
- 仅在本地主机上可见,因此不会降低网络速度
- 获取相当多的数据(30MB 作为一个大型 numpy 数组)作为输入,并输出相对较小的数据量(大约 1MB)。
我做了一个快速测试并使用 Flask 开发服务器运行它,它按预期工作。被红色的字吓到了WARNING: This is a development server. Do not use it in a production deployment.
我尝试将其放在 WSGI 服务器后面,但 Waitress 和 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)
[编辑:这个问题的原始版本缺少参数threaded=False, processes=1
在通话中app.run
上面的行为与下面的 GUnicorn 和 Waitress 不同,它们被迫单线程/进程;我现在添加了它,并重新测试,结果没有改变,Flask 服务器在此更改后仍然很快 - 如果有的话,更快]
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()
女服务员服务器.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,则传输 30MB)我得到以下计时:
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 次迭代中每次分配内存的时间),而 Waitress 和随着传输数据的增加,GUnicorn 的速度受到显着影响。
问题
此时,我有几个问题:
- Waitress 和 GUnicorn 是否会对提交的数据进行某种需要时间的检查?如果是这样,有办法禁用它们吗?
- Is there an important reason why Waitress / GUnicorn are better than the Flask development server, or could I just use it for my use case? As mentioned:
- 我不关心安全;这些仅从本地主机可见,并且我生成在我的另一个进程中进入它们的数据
- 我积极希望一个进程/线程同时运行,这是 Flask 开发服务器的唯一可能性,并且我对其他服务器强制执行。这是因为我的真实应用程序将在 GPU 上运行,如果我有很多进程/线程,我很快就会耗尽内存
- 我知道在任何时间点,到该服务器的连接数都会很少(可能是 4 个,当然不会超过 8 个),因此扩展也不是问题。
- ...但这将在生产中,所以我需要一些可靠和稳定的东西。