You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask+OpenCV实时视频流阻塞问题求助:服务器锁定无法执行其他操作

解决Flask+OpenCV视频流阻塞服务器的问题

嘿,作为过来人太懂你这个坑了——刚用Flask和OpenCV做摄像头流的时候,我也碰到过服务器被死死卡住,除了视频流啥请求都处理不了的情况!核心原因其实很简单:Flask默认是单线程同步运行的,当你的视频流路由里一直在循环推帧时,整个线程都被这个循环占满了,其他请求根本挤不进来。下面给你几个新手友好的解决方案,从简单到进阶都有:

方案1:开启Flask多线程模式

这是最快速的临时解决办法,只需要修改启动参数,让Flask支持同时处理多个请求:

if __name__ == '__main__':
    app.run(threaded=True)  # 开启多线程,每个请求分配独立线程

这样当用户访问视频流时,这个请求会占用一个线程,其他请求(比如首页、API接口)可以用另外的线程处理,不会被阻塞。不过这个方案有个小缺点:如果有多个用户同时看视频流,线程数会越来越多,性能可能受影响,但对新手测试来说足够用了。

方案2:用后台线程维护帧缓冲区(推荐)

这个方法更优雅,把摄像头捕获帧的逻辑放到后台线程,路由只负责读取最新的帧返回,彻底避免路由被阻塞:

import cv2
from flask import Flask, Response
import threading

app = Flask(__name__)

# 全局变量存储最新的摄像头帧
latest_frame = None
# 线程锁:防止多个线程同时读写帧导致数据混乱
frame_lock = threading.Lock()

def capture_camera_frames():
    """后台线程:持续捕获摄像头帧并更新全局变量"""
    global latest_frame
    # 打开默认摄像头(参数0对应系统默认摄像头)
    cap = cv2.VideoCapture(0)
    
    while True:
        ret, frame = cap.read()
        if not ret:
            # 摄像头读取失败时退出循环
            break
        
        # 加锁更新最新帧,避免读写冲突
        with frame_lock:
            latest_frame = frame
    
    # 程序退出时释放摄像头资源
    cap.release()

def generate_video_stream():
    """生成HTTP视频流格式的响应内容"""
    global latest_frame
    while True:
        with frame_lock:
            if latest_frame is None:
                # 还没捕获到帧时等待
                continue
            # 将OpenCV的BGR格式帧转换成JPEG字节流
            ret, buffer = cv2.imencode('.jpg', latest_frame)
            frame_bytes = buffer.tobytes()
        
        # 按照HTTP流媒体的格式返回帧
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')

# 路由:返回视频流
@app.route('/video_feed')
def video_feed():
    return Response(
        generate_video_stream(),
        mimetype='multipart/x-mixed-replace; boundary=frame'
    )

# 测试用的首页路由
@app.route('/')
def index():
    return '<h1>摄像头实时流测试</h1><img src="/video_feed" width="640" height="480">'

if __name__ == '__main__':
    # 启动后台线程捕获摄像头帧,daemon=True表示随主程序退出自动结束
    threading.Thread(target=capture_camera_frames, daemon=True).start()
    # 开启多线程模式运行Flask
    app.run(threaded=True, debug=True)

这个方案的优势:

  • 摄像头捕获逻辑在后台独立运行,不会占用请求线程
  • 每个访问视频流的用户只会读取最新的帧,不会重复捕获摄像头资源
  • 线程锁保证了多线程环境下帧数据的安全性

方案3:生产环境用Gunicorn多进程部署

如果你的项目要放到生产环境,Flask自带的开发服务器就不够用了,推荐用Gunicorn(一个生产级的Python WSGI服务器),通过多进程来处理并发请求:

  1. 先安装Gunicorn:
pip install gunicorn
  1. 用多进程模式启动你的Flask应用:
gunicorn --workers=4 app:app

这里--workers=4表示开启4个工作进程,可以根据你的服务器CPU核心数调整(一般设置为核心数的2倍)。每个进程可以独立处理请求,彻底解决阻塞问题。

注意事项:

  • 多进程环境下,全局变量无法在进程间共享,如果你需要多个进程访问同一份帧数据,可以用Redis或者消息队列(比如RabbitMQ)来存储帧,但这对新手来说有点复杂,先从前面的方案入手就好
  • 生产环境记得关闭Flask的debug=True模式,避免安全风险

试试上面的方法,先从方案2开始,这个最适合新手学习和实践,解决阻塞问题的同时还能理解Flask的线程处理逻辑。如果还有细节问题,随时问就行!

内容的提问来源于stack exchange,提问作者user8611018

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:23:34