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

Flask结合Matplotlib报错RuntimeError:主线程不在主循环中

Flask路由线程问题与Matplotlib主线程绘图解决方案

首先直接回答你的第一个问题:是的,Flask的默认服务器(Werkzeug)在默认配置下是多线程运行的——每个进来的请求都会被分配到一个独立的线程中处理,所以你的sendOutput路由函数确实是在非主线程里执行的。这也是你遇到Matplotlib绘图保存问题的核心原因之一,因为Matplotlib的大多数后端(比如默认的TkAgg、Agg)都不是线程安全的,在子线程里调用fig.savefig很容易触发异常或渲染错误。

接下来给你两种实用方案,帮你让fig.savefig运行在主线程:

方案1:使用线程安全队列实现任务调度

这是最可靠的轻量方案,思路是让路由线程只负责生成绘图所需的数据与配置,把实际的保存任务放到线程安全队列中,由主线程专门处理队列里的保存请求。

步骤与示例代码:

  1. 导入Python标准库的queue和threading模块,创建全局的线程安全队列
  2. 在主线程启动一个后台线程,持续监听队列,一旦收到任务就执行fig.savefig
  3. 路由函数中仅准备绘图数据,将保存任务(比如fig对象、保存路径)放入队列
from flask import Flask
import queue
import threading
import matplotlib.pyplot as plt

app = Flask(__name__)
# 创建线程安全的保存任务队列
save_queue = queue.Queue()

def fig_save_worker():
    """主线程后台运行的任务处理函数,专门负责图片保存"""
    while True:
        fig, save_path = save_queue.get()
        try:
            fig.savefig(save_path)
            plt.close(fig)  # 及时释放资源,避免内存泄漏
        except Exception as e:
            print(f"图片保存失败: {str(e)}")
        finally:
            save_queue.task_done()

# 在启动Flask前启动后台任务线程(daemon=True表示随主线程退出而终止)
threading.Thread(target=fig_save_worker, daemon=True).start()

@app.route('/open', methods=['GET', 'POST'])
def sendOutput():
    global loss,a2,xP,yP,scale,sess,fig 
    test_X,test_Y = own_model.getEvaluateData(scale) 
    cost,ans = sess.run([loss,a2],feed_dict={xP:test_X,yP:test_Y}) 
    # 假设你已经完成了fig的绘图逻辑
    # 将保存任务放入队列,由主线程的worker处理
    save_queue.put((fig, './output_result.png'))
    # 返回请求响应
    return {"cost": cost, "status": "图片保存任务已提交"}

if __name__ == '__main__':
    app.run()  # 默认threaded=True,可省略

方案2:切换Matplotlib为无GUI后端(应急用,不推荐复杂场景)

如果你不想调整代码架构,可以尝试强制Matplotlib使用非GUI的后端(比如Agg),并确保整个绘图流程(创建fig、绘图、保存)在同一个线程中完成。但注意:即使切换后端,Matplotlib的状态机(当前figure、axes等)依然不是线程安全的,多请求并发时仍可能出问题。

在代码最开头添加:

import matplotlib
matplotlib.use('Agg')  # 切换到无GUI后端
import matplotlib.pyplot as plt

另外补充:TensorFlow的Session对象本身是线程安全的(只要不同时在同一个会话中调用sess.run),所以你在路由线程中调用sess.run是没问题的。如果后续有更复杂的多线程操作,也可以考虑把会话封装到线程本地存储中,避免全局变量冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:03:11