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"]
验证步骤
- 修改代码后,先在本地验证功能正常。
- 重新构建镜像:
docker build -t plot-app . - 运行容器:
docker run -p 8000:8000 plot-app - 访问
http://localhost:8000/plot.png,等待check_time触发更新,确认图片是否刷新。
内容的提问来源于stack exchange,提问作者PetersServer1
相关产品推荐
相关产品推荐

