Flask(Gunicorn) 多次刷新后无法提供应用程序

问题描述 投票:0回答:1

我正在测试一个 Flask Web 应用程序,它应该在网页上显示 mjpeg 视频流。

客户端使用带有 src=/video_srcimg 选项卡。 在服务器端,我使用 /video_src 的处理程序,它从生成器函数返回多部分数据

server = Flask(__name__)
camera = Camera("path to network camera stream") # global camera object instantiated once 

@server.route("/video_src")
def video_src():
    return Response(camera.gen(), mimetype="multipart/x-mixed-replace; boundary=frame")

# gen function from camera class. The self.frame value is the actual jpeg bytes. It is calculated
# in a separate thread and kept updated to the latest frame by the camera class.
    def gen(self):
        while True:
            print(f"id: {threading.get_ident()}")
            yield (
                b"--frame\r\n"
                b"Content-Type: image/jpeg\r\n\r\n" + self.frame + b"\r\n\r\n"
            )
            time.sleep(0.25)

我正在使用gunicorn来运行应用程序:

gunicorn --threads 3 --workers 1 --bind 0.0.0.0:5000 app:server

首次在浏览器中访问应用程序时,一切正常。我可以在日志中看到 gen() 函数以 0.25 秒的间隔重复调用单个线程 id。第一次刷新后,网站再次正常加载,我从生成函数中看到 2 个不同的散布线程 ID。一段时间后,旧线程 id 停止打印,只有新线程 id 打印继续。第二次刷新时也会发生同样的情况,但第三次刷新时网站将停止加载。来自 gen() 的日志也停止了,但从其他日志来看,应用程序本身似乎很好。 15 分钟后我才看到错误,现在网站可以再次加载

TimeoutError: [Errno 110] Connection timed out

如果我增加 Gunicorn 线程,我可以在网站停止加载之前进行更多次刷新。 因此,就好像 Gunicorn 线程正在耗尽但从未被回收。这里可能是什么原因/修复,也许需要更改gunicorn配置值?

编辑 这似乎适用于我的 x86_64 Mac,但不适用于 aarch64 Rpi。两台机器都使用相同版本的 Flask(3.0.0) 和 Werkzeug(3.0.1)

python flask video-streaming gunicorn
1个回答
0
投票

无法找出根本问题,但能够通过以下方式解决它:

defframe_generator(input_stream): 尝试: 而真实: 如果 input_stream.read() 不是 None: 引发 GeneratorExit 屈服 ( b"--框架 ” b“内容类型:图像/jpeg “+camera.get_frame()+b” ” ) 睡眠时间(0.9) 除了 GeneratorExit: logger.info("退出生成")

@server.route(“/video_src”) def video_src(): """注意:使用 input_stream 是一种 hack,因为当浏览器关闭或刷新时,应该关闭生成器 并且运行它的线程被释放。这在 x86_64 Mac 上有效,但在 aarch64 Rpi 上似乎不会发生。因此 在 Rpi 上,线程永远不会被释放,所有线程都会在重新加载/刷新时消耗。但这个黑客不起作用 使用gunicorn时所以应该直接使用python来运行""" 流=请求.input_stream os.set_blocking(stream.fileno(), False) 帧=frame_generator(流) 返回响应(stream_with_context(帧),mimetype =“multipart / x-mixed-replace;边界=帧”)

© www.soinside.com 2019 - 2024. All rights reserved.