Waitress和GUnicorn大数据输入比Flask开发服务器慢很多

2023-11-22

问题描述

我正在尝试创建一个 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 个),因此扩展也不是问题。
    • ...但这将在生产中,所以我需要一些可靠和稳定的东西。

这很有趣。也许这可以解释这个问题。

  1. 通过使用 time.time() 我发现request.data在网络应用程序中花费不同的时间。当使用 Gunicorn 时,这会花费超过 95% 的时间,即 0.35 秒。当使用 Flask Web 应用程序时,这花费了大约 0.001 秒。

  2. 我走进它的包裹。我发现大部分时间都花在werkzeug/wrappers/base_request.py 456 line这是

    rv = self.stream.read()

    使用 Flask 开发服务器时。这self.stream is werkzeug.wsgi.LimitedStream。这条线花费了大约0.001s。

    使用枪角兽时。这self.stream is gunicorn.http.body.Body。这将花费超过0.3秒。

  3. 我步入gunicorn/http/body.py。第 214-218 行

     while size > self.buf.tell():
         data = self.reader.read(1024)
         if not data:
             break
         self.buf.write(data)
    

    这花费了超过0.3s。

  4. 我尝试将上面的代码更改为self.buf.write(self.reader.read(size))。这使得它花费了 0.07 秒。

  5. 我将上面的代码分成

     now = time.time()
     buffer = self.reader.read(size)
     print(time.time() - now)
     now = time.time()
    

    我发现第一行成本为 0.053。第二行成本 0.017。

我想我已经找到原因了。

首先,gunicorn 使用 io.BytesIO 将原始字节包装到他的特殊对象中。

其次,gunicorn 使用 while 循环读取字节,这会花费更多时间。

我猜这些代码的目的是支持高并发。

对于你的情况,我认为你可以直接使用 gevent 。

from gevent.pywsgi import WSGIServer
from basic_flask_app import app

http_server = WSGIServer(('', 80), app)
http_server.serve_forever()

这要快得多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Waitress和GUnicorn大数据输入比Flask开发服务器慢很多 的相关文章

  • 从数据框中按索引删除行

    我有一个数组wrong indexes train其中包含我想从数据框中删除的索引列表 0 63 151 469 1008 要删除这些索引 我正在尝试这样做 df train drop wrong indexes train 但是 代码失败
  • 使用 python 进行串行数据记录

    Intro 我需要编写一个小程序来实时读取串行数据并将其写入文本文件 我在读取数据方面取得了一些进展 但尚未成功地将这些信息存储在新文件中 这是我的代码 from future import print function import se
  • 如何在序列化器创建方法中获取 URL Id?

    我有以下网址 url r member P
  • Django 模型在模板中不可迭代

    我试图迭代模型以获取列表中的第一个图像 但它给了我错误 即模型不可迭代 以下是我的模型和模板的代码 我只需要获取与单个产品相关的列表中的第一个图像 模型 py class Product models Model title models
  • 如何在 pytest 中将单元测试和集成测试分开

    根据维基百科 https en wikipedia org wiki Unit testing Description和各种articles https techbeacon com devops 6 best practices inte
  • Pandas 中允许重复列

    我将一个大的 CSV 包含股票财务数据 文件分割成更小的块 CSV 文件的格式不同 像 Excel 数据透视表之类的东西 第一列的前几行包含一些标题 公司名称 ID 等在以下列中重复 因为一家公司有多个属性 而不是一家公司只有一栏 在前几行
  • 填充两个函数之间的区域

    import matplotlib pyplot as plt import numpy as np def domain x np arange 0 10 0 001 f1 lambda x 2 x x 2 0 5 plt plot x
  • Pandas 数据帧到 numpy 数组 [重复]

    这个问题在这里已经有答案了 我对 Python 很陌生 经验也很少 我已经设法通过复制 粘贴和替换我拥有的数据来使一些代码正常工作 但是我一直在寻找如何从数据框中选择数据 但无法理解这些示例并替换我自己的数据 总体目标 如果有人真的可以帮助
  • 以同步方式使用 FastAPI,如何获取 POST 请求的原始正文?

    在中使用 FastAPIsync not async模式 我希望能够接收 POST 请求的原始 未更改的正文 我能找到的所有例子都显示async代码 当我以正常同步方式尝试时 request body 显示为协程对象 当我通过发布一些内容来
  • 使用 Python pandas 计算调整后的成本基础(股票买入/卖出的投资组合分析)

    我正在尝试对我的交易进行投资组合分析 并尝试计算调整后的成本基础价格 我几乎尝试了一切 但似乎没有任何效果 我能够计算调整后的数量 但无法获得调整后的购买价格有人可以帮忙吗 这是示例交易日志原始数据 import pandas as pd
  • 为什么在 Python 2.4 中使用 Unicode 数据会出现 ASCII 编码错误,而在 2.7 中却不会?

    我有一个程序 当在 Python 2 7 中运行时 会生成正确的 Unicode 输出到标准输出 当在 Python 2 4 中运行时 我得到UnicodeEncodeError ascii codec can t encode chara
  • 对图像块进行多重处理

    我有一个函数必须循环遍历图像的各个像素并计算一些几何形状 此函数需要很长时间才能运行 在 24 兆像素图像上大约需要 5 小时 但似乎应该很容易在多个内核上并行运行 然而 我一生都找不到一个有据可查 解释充分的例子来使用 Multiproc
  • TensorFlow的./configure在哪里以及如何启用GPU支持?

    在我的 Ubuntu 上安装 TensorFlow 时 我想将 GPU 与 CUDA 结合使用 但我却停在了这一步官方教程 http www tensorflow org get started os setup md 这到底是哪里 con
  • 将 matplotlib 颜色图集中在特定值上

    我正在使用 matplotlib 颜色图 seismic 绘制绘图 并且希望白色以 0 为中心 当我在不进行任何更改的情况下运行脚本时 白色从 0 下降到 10 我尝试设置 vmin 50 vmax 50 但在这种情况下我完全失去了白色 关
  • 如何在 python 中没有 csv.reader 迭代器的情况下解析单行 csv 字符串?

    我有一个 CSV 文件 需要重新排列和重新编码 我想跑 line line decode windows 1250 encode utf 8 在由 CSV 读取器解析和分割之前的每一行 或者我想自己迭代行 运行重新编码 并仅使用单行解析表单
  • 如何在 OSX 上安装 numpy 和 scipy?

    我是 Mac 新手 请耐心等待 我现在使用的是雪豹 10 6 4 我想安装numpy和scipy 所以我从他们的官方网站下载了python2 6 numpy和scipy dmg文件 但是 我在导入 numpy 时遇到问题 Library F
  • 默认情况下,Keras 自定义层参数是不可训练的吗?

    我在 Keras 中构建了一个简单的自定义层 并惊讶地发现参数默认情况下未设置为可训练 我可以通过显式设置可训练属性来使其工作 我无法通过查看文档或代码来解释为什么会这样 这是应该的样子还是我做错了什么导致默认情况下参数不可训练 代码 im
  • Tkinter - 浮动窗口 - 调整大小

    灵感来自this https stackoverflow com a 22424245 13629335问题 我想为我的根窗口编写自己的调整大小函数 但我刚刚注意到我的代码显示了一些性能问题 如果你快速调整它的大小 你会发现窗口没有像我希望
  • Elastic Beanstalk 中的 enum34 问题

    我正在尝试在 Elastic Beanstalk 中设置 django 环境 当我尝试通过requirements txt 文件安装时 我遇到了python3 6 问题 File opt python run venv bin pip li
  • 迭代 pandas 数据框的最快方法?

    如何运行数据框并仅返回满足特定条件的行 必须在之前的行和列上测试此条件 例如 1 2 3 4 1 1 1999 4 2 4 5 1 2 1999 5 2 3 3 1 3 1999 5 2 3 8 1 4 1999 6 4 2 6 1 5 1

随机推荐

  • 您可以通过 Flex 使用 Amazon S3 吗?

    由于缺少 clientaccesspolicy xml 通过 Flex 使用 Amazon S3 似乎存在问题 有什么解决办法吗 Edit 下面的两个答案都很棒并且有效 我都赞成 我不会为这个问题指定答案 因为它们都有效 您可以通过 Fle
  • 在 VB 中键入时,如何使智能感知上的 Enter 键的反应方式与 Visual Studio 中的 C# 中的反应方式相同?

    我使用的是 Visual Studio 2008 并且习惯了 C 当智能感知弹出时 我通过按 Enter 键选择我想要的内容 它不会跳到下一行 在 VB 中 当我在智能感知上按下回车键时 我会跳转到下一行 有谁知道这个智能感知选项的设置可能
  • 是否可以在 Emacs 中用文本替换边缘位图?

    我很想用简单 雅致的文本 甚至可能是一个很好的 unicode 字符 例如 u2026省略 这可能吗 不它不是 边缘 位图 实际上是位图 即覆盖在边缘上的 0 1 位向量 没有办法直接将任意 unicode 字符渲染到边缘上 您可以做的就是
  • IN 子句中的通配符

    SQL 我想在 IN 子句中使用通配符 但没有得到我期望的结果 我的查询是这样的 SELECT DISTINCT ID FROM INST WHERE TYPE in IP International 请帮助解决这个问题 解决方案应该是使用
  • Python for 循环中的“pass”和“continue”有区别吗?

    两个Python关键字之间有什么显着差异吗continue and pass就像例子中一样 for element in some list if not element pass and for element in some list
  • 可以改变JButton的形状吗?

    是否可以将 JButton 的形状从矩形更改为圆形 Sean Cogan 提供的链接就是您所需要的 如果您想要简短 请设置一个图像 圆形或任何您希望按钮看起来相似的形状 使用setIcon然后在 JButton button1 上设置这些值
  • 获取类转换异常,其中两个类完全相同

    我正在做一个 JBoss SEAM 项目 当我查看表单时 我收到此错误 java lang ClassCastException it cogitoweb csi entity csiorelav CsiTipoLav cannot be
  • Unix 域:connect():没有这样的文件或目录

    如标题所述 我的连接 调用具有相应地址的 unix 域类型套接字会导致错误ENOENT 没有这样的文件或目录 两个套接字已正确初始化 并且相应地创建并绑定了套接字文件 服务器和客户端套接字在不同的进程中运行 尽管客户端进程是 fork 和
  • 使用标记列表构建抽象语法树

    我想从令牌列表构建 AST 我正在制作一种脚本语言 并且已经完成了词法分析部分 但我不知道如何创建 AST 所以问题是 我该如何采取这样的事情 WORD int WORD x SYMBOL NUMBER 5 SYMBOL 并将其转换为抽象语
  • GWT - 在单元树中添加和删除节点

    这里我有一个完整且非常简单的示例来动态添加 删除 单元树的节点 我的例子效果不太好 似乎有 是刷新问题 只有关闭 展开节点才会显示正确的 结果 我在这个论坛上也没有找到适合这个问题的答案 也许有人可以尝试我的例子并告诉我问题出在哪里 任何其
  • 在一个 JFrame 中使用两个 JPanel

    我正在尝试创建一个程序 允许用户单击按钮将某些内容放入JPanel并允许他们移动该物品 我已经找到了一个很好的布局来允许移动组件 请参阅this关联 但是 我只是好奇创建这样的布局的最佳方法 我的希望是有这样的东西 我怎样才能做到这一点 我
  • Python 读取输入的最快方法

    我想读取一个包含整数列表列表的巨大文本文件 现在我正在执行以下操作 G with open test txt r as f for line in f G append list map int line split 然而 大约需要 17
  • 实时更新 Google Compute Engine 实例类型

    我想知道您是否可以将一个实例的类型更改为另一种实例 例如 n1 标准 1 到 n1 标准 2 我在文档中没有看到任何内容 但可能我错过了一些东西 如果这是不可能的 我如何处理这个问题 还有另一种方法可以进行此更改 您可以停止机器 对其进行编
  • AngularJS ngTable 按日期过滤

    我正在尝试在我的应用程序中设置 ngTable 但它不支持按日期过滤 而且我不知道如何实现它 我最初将数据中的日期作为时间戳 这使我能够由于时间戳的增量性质而对列进行正确排序 但显然我无法输入 9 月并过滤数据 Example row da
  • 两个文本文件的内连接

    希望对两个不同的文本文件执行内部联接 基本上我正在寻找与 GNU join 程序等效的内部联接 这样的事情存在吗 如果没有 则awk or sed解决方案将是最有帮助的 但我的第一选择是 Linux 命令 这是我想要做的事情的一个例子 fi
  • 在应用程序购买恢复交易中,我无法弄清楚代码

    我在我的编码中添加了应用程序内购买 它在购买时运行良好 但当我尝试在删除并再次安装应用程序时添加 Restore Transaction 代码时 它会出现错误并且应用程序关闭 我添加了以下编码 在 onCreate 我写的 startSer
  • MySQL 创建外键的语法

    创建外键时这种语法是否正确 create table department departmentID int not null auto increment primary key name varchar 30 type InnoDB c
  • .NET 中的单元测试 System.Threading.Timer

    如何在 NET中基于System Threading Timer对计时器进行单元测试 System Threading Timer有一个回调方法 您可以通过不实际创建直接依赖项来对其进行单元测试System Threading Timer
  • 使用WebService自动捕获所有未处理的异常

    我有一个 C WebService 应用程序 我想在其中捕获应用程序抛出的所有未处理的异常 我怎样才能做到这一点 由于某种原因 Web 服务不会触发 Application Error 事件 请参阅其他问题 杰夫 阿特伍德先生本人也发表了一
  • Waitress和GUnicorn大数据输入比Flask开发服务器慢很多

    问题描述 我正在尝试创建一个 Flask 应用程序 它应该 仅在本地主机上可见 因此不会降低网络速度 获取相当多的数据 30MB 作为一个大型 numpy 数组 作为输入 并输出相对较小的数据量 大约 1MB 我做了一个快速测试并使用 Fl