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

双线程启动异常:Flask服务与摄像头线程无法同时运行求助

问题修复方案

核心问题分析

你的代码里有几个关键错误导致线程无法同时运行:

  1. 线程创建方式错误:创建线程时用了target=vd(),这会直接在主线程里执行vd函数,而不是把函数作为线程的执行目标。正确写法是target=vd(不带括号)。
  2. 摄像头线程被阻塞:vd函数里启动Web线程后调用了th.join(),这会让摄像头线程一直等待Web线程结束,但Flask的app.run()是阻塞式的,摄像头循环根本没机会执行。
  3. Flask启动条件无效:webWork里的if __name__ == "__main__":判断,在线程调用时不会触发,导致服务器无法启动。
  4. 帧数据格式错误:gen_frames直接把OpenCV的帧对象拼接进响应,必须先编码成JPEG字节流才能返回。
  5. 多线程读写冲突:全局frame被两个线程同时读写,需要加锁避免数据异常。

修复后的完整代码

#!/usr/bin/env python
from datetime import datetime
from flask import Flask, render_template, Response, request
import numpy as np
import cv2
from threading import Thread, Lock

# Initialize the Flask app
app = Flask(__name__)
pwm_az = 0
pwm_tilt = 0
# 全局帧变量+锁
frame = None
frame_lock = Lock()

def vd():
    global frame
    vid = cv2.VideoCapture(0)
    print("摄像头线程已启动")
    
    while True:
        ret, current_frame = vid.read()
        if not ret:
            break
        
        # 加锁更新全局帧
        with frame_lock:
            frame = current_frame.copy()
        
        # 显示本地预览
        cv2.imshow('frame', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    vid.release()
    cv2.destroyAllWindows()

def gen_frames():
    global frame
    while True:
        # 加锁读取全局帧
        with frame_lock:
            if frame is None:
                continue
            # 将帧编码为JPEG字节流
            ret, buffer = cv2.imencode('.jpg', frame)
            if not ret:
                continue
            frame_bytes = buffer.tobytes()
        
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')

@app.route('/')
def index():
    return render_template('index_2.html')

@app.route('/video_feed')
def video_feed():
    return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

def webWork():
    # 去掉多余的判断,直接启动Flask
    app.run(host="localhost", port=8086, debug=False)  # debug=True会重启线程,建议关闭

# 正确创建线程:传入函数引用,不带括号
thread_videoWork = Thread(target=vd, args=())
thread_webWork = Thread(target=webWork, args=())

# 启动两个线程
thread_videoWork.start()
thread_webWork.start()

# 等待线程结束(可选,避免主线程提前退出)
thread_videoWork.join()
thread_webWork.join()

关键修改说明

  • 线程创建:把target=vd()改成target=vd,确保函数在线程内执行,而非主线程提前执行。
  • 移除阻塞逻辑:删掉vd函数里启动Web线程和join()的代码,让摄像头线程专注于采集帧。
  • Flask启动:去掉webWork里的if __name__ == "__main__":判断,直接启动服务器;关闭debug=True,避免Flask debug模式自动重启线程导致重复启动。
  • 帧编码:在gen_frames里用cv2.imencode把OpenCV帧转成JPEG字节流,符合HTTP响应的格式要求。
  • 线程锁:用Lock()保护全局frame的读写操作,避免多线程同时操作导致的帧损坏或程序异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 09:35:15