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

Docker部署Python多线程绘图更新失效问题求助

问题:Docker部署后Python多线程绘图停止更新

本地IDE运行Python多线程绘图代码完全正常:每当check_time函数返回True时,绘图会自动更新。但通过Docker部署后,plot.png仅能初始生成并在/plot.png路径展示,后续不再更新,说明update_plot线程已停止执行。

本地运行正常的代码

import matplotlib.pyplot as plt
import time
from threading import Thread
from flask import Flask, send_file
from config import *
import mysql.connector
import pandas as pd
from support_analysis import *
import datetime

app = Flask(__name__)

def update_plot():
    while True:
        if check_time(consistent=True):
            #print("script is updating")
            result = download_data()
            right_pred_rise, longest_rise, right_pred_fall, longest_fall \
                = print_metrics_over_time(df=result)

            ml_1pred, ml2_pred = get_latest_pred(result)

            result = result[['return', 'return_static_invest']]
            timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")


            # Create the plot
            fig, ax = plt.subplots()
            result.plot(ax=ax)

            # Add the vertical lines
            plt.axvline(x=result.index[longest_rise[0]], color='green')
            plt.axvline(x=result.index[longest_rise[1]], color='green')
            plt.axvline(x=result.index[longest_fall[0]], color='red')
            plt.axvline(x=result.index[longest_fall[1]], color='red')

            # Add the red dot to the latest index
            latest_index = len(result) - 1
            ax.scatter(result.index[latest_index], ml_1pred, color='cornflowerblue')

            # Add the blue dot to the latest index
            ax.scatter(result.index[latest_index], ml2_pred, color='coral')

            plt.title(label='Bot vs buy and hold', fontweight='bold')
            plt.text(0.95, 0.01, timestamp, transform=plt.gcf().transFigure, ha='right', fontsize=8)

            plt.savefig('plot.png')

@app.route('/plot.png')
def plot():
    return send_file('plot.png', mimetype='image/png')


if __name__ == '__main__':
    # Start the update thread
    t = Thread(target=update_plot)
    t.start()

    # Run the web server
    app.run()

Dockerfile内容

FROM python:3.10

COPY main.py main.py
COPY config.py config.py
COPY support_analysis.py support_analysis.py
COPY numbers.pkl numbers.pkl
COPY requirements.txt requirements.txt


RUN pip install -r requirements.txt

RUN pip install gunicorn

EXPOSE 8000

# Run the WSGI server
CMD ["gunicorn"  , "--bind", "0.0.0.0:8000", "main:app"]

原因排查

  • 线程启动逻辑未执行:本地通过if __name__ == '__main__':启动线程,但Gunicorn运行时直接导入main:app,不会触发该代码块,导致update_plot线程从未启动。
  • Matplotlib后端适配问题:Docker环境无图形界面,Matplotlib默认交互式后端会报错,导致线程崩溃。
  • 绘图资源未释放:每次绘图后未关闭图形对象,内存泄漏可能导致线程挂起。

解决方案

1. 修正线程启动逻辑

将线程启动代码移出__main__块,改为Flask应用初始化时执行:

# 新增线程启动函数
def start_update_thread():
    t = Thread(target=update_plot, daemon=True)  # 设置为守护线程,随主进程退出
    t.start()

# 在app创建后立即启动线程
start_update_thread()

# 保留本地测试用的app.run()
if __name__ == '__main__':
    app.run()

2. 配置Matplotlib无图形后端

在代码开头添加后端配置,适配Docker无GUI环境:

import matplotlib
matplotlib.use('Agg')  # 使用非交互式后端,无需图形界面
import matplotlib.pyplot as plt

3. 释放绘图资源

在plt.savefig后添加图形关闭代码,避免内存泄漏:

plt.savefig('plot.png')
plt.close(fig)  # 关闭当前图形,释放资源

4. 优化Dockerfile(可选)

简化复制命令,将gunicorn加入requirements.txt避免单独安装:

FROM python:3.10

COPY . .

RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 8000

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "main:app"]

验证步骤

  1. 修改代码后,先在本地验证功能正常。
  2. 重新构建镜像:docker build -t plot-app .
  3. 运行容器:docker run -p 8000:8000 plot-app
  4. 访问http://localhost:8000/plot.png,等待check_time触发更新,确认图片是否刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:21:47