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服务器),通过多进程来处理并发请求:
- 先安装Gunicorn:
pip install gunicorn
- 用多进程模式启动你的Flask应用:
gunicorn --workers=4 app:app
这里--workers=4表示开启4个工作进程,可以根据你的服务器CPU核心数调整(一般设置为核心数的2倍)。每个进程可以独立处理请求,彻底解决阻塞问题。
注意事项:
- 多进程环境下,全局变量无法在进程间共享,如果你需要多个进程访问同一份帧数据,可以用Redis或者消息队列(比如RabbitMQ)来存储帧,但这对新手来说有点复杂,先从前面的方案入手就好
- 生产环境记得关闭Flask的
debug=True模式,避免安全风险
试试上面的方法,先从方案2开始,这个最适合新手学习和实践,解决阻塞问题的同时还能理解Flask的线程处理逻辑。如果还有细节问题,随时问就行!
内容的提问来源于stack exchange,提问作者user8611018
相关产品推荐
相关产品推荐

