POST请求响应时间激增

1 投票
0 回答
40 浏览
提问于 2025-04-12 06:34

在我的项目中,我需要将图片以字节的形式上传到一个接口,然后在一定时间内处理这些图片。这些图片的分辨率是600x600,每张大约700千字节,格式是png。我创建了一个简单的flask应用,里面有一个接口。这个应用是通过waitress来提供服务的。

问题是,有时候接口的响应时间会突然增加很多倍。因为我需要在一定的时间内完成处理,这种突发的延迟可能会导致严重的错误。

我对POST请求进行了性能分析,发现当出现延迟时,有两个函数的执行时间比正常情况要长:

正常情况

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     2    0.000    0.000    0.000    0.000 {method 'sendall' of '_socket.socket' objects}
     1    0.004    0.004    0.004    0.004 {method 'recv_into' of '_socket.socket' objects}

延迟情况

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     2    0.008    0.004    0.008    0.004 {method 'sendall' of '_socket.socket' objects}
     1    0.012    0.012    0.012    0.012 {method 'recv_into' of '_socket.socket' objects}

这些延迟的原因是什么?有没有办法解决?

复现问题的代码:

# app.py
import numpy as np
from flask import Flask, request


def create_app():
    app = Flask(__name__)

    @app.route("/endpoint")
    def endpoint():
        data = request.data
        img_arr = np.frombuffer(data, dtype=np.uint8)
        # ...
        return {"foo": "bar"}

    return app
# wsgi.py
from waitress import serve

from app import create_app


def main():
    app = create_app()
    serve(app, host="0.0.0.0", port="9009")


if __name__ == "__main__":
    main()
# send.py

from pathlib import Path

import numpy as np
import requests
from PIL import Image


def main():
    img_paths = list(Path("images").rglob("*.png"))
    ses = requests.Session()
    speeds = []
    for img_path in img_paths:
        img_arr = np.asarray(Image.open(img_path))
        response = ses.post(url='http://0.0.0.0:9009/endpoint', data=img_arr.tobytes())
        speeds.append(response.elapsed.total_seconds())


if __name__ == "__main__":
    main()

我执行了python wsgi.py,然后在另一个终端执行python send.py

Python和相关包的版本:

python==3.8.18

Flask==3.0.2
numpy==1.24.4
pillow==10.2.0
requests==2.31.0
waitress==3.0.0

对1,000张图片进行了三次独立的性能测试:

第一次

第二次

第三次

我尝试像这样定义自己的socket:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
s.bind(("0.0.0.0" 9009))
serve(app, sockets=[s])

但这完全没有帮助。我对网络知识了解不多。

0 个回答

暂无回答

撰写回答