多线程场景下Matplotlib关闭后图形窗口卡顿无法消失的解决咨询
解决Matplotlib多线程提交任务后第二个窗口无法正常关闭的问题
问题分析
你的代码在MacOS环境下出现第二个绘图窗口关闭卡顿的问题,核心原因有三点:
- 每次绘图任务重复导入
matplotlib.pyplot,导致Matplotlib内部状态混乱; - 绘图完成后未主动清理窗口资源,MacOSX后端的GUI残留无法正常回收;
- 主线程的无限空轮询占用CPU,阻碍了GUI事件循环的收尾处理。
解决方案
以下是针对性的修改方案:
1. 统一管理Matplotlib导入与资源清理
在主线程提前导入plt,避免重复导入导致的状态冲突;每个绘图任务完成后强制关闭所有窗口,释放资源。
2. 优化主线程队列轮询逻辑
将空轮询改为阻塞等待任务,减少CPU占用;设置任务计数,所有任务完成后自动退出循环,避免无意义的循环占用资源。
3. 简化任务代码
去掉任务代码中的重复导入语句,减少不必要的初始化操作。
修改后的完整代码
import queue import threading import matplotlib.pyplot as plt def runScriptMainThread(code): print(threading.current_thread()) print("Code : ", code) try: exec(code) finally: # 无论任务是否成功,都清理所有Matplotlib窗口资源 plt.close('all') def runScript(code): callback_queue.put(lambda: runScriptMainThread(code)) callback_queue = queue.Queue() # 简化任务代码,去掉重复的import语句 task1 = "plt.plot([1, 2, 3, 4]);plt.ylabel('some numbers');plt.show(block=True);" task2 = "plt.plot([5, 6, 3, 4]);plt.ylabel('some numbers');plt.show(block=True);" threading.Thread(target=runScript, args=(task1,)).start() threading.Thread(target=runScript, args=(task2,)).start() # 处理完所有任务后退出循环,避免无限空轮询 total_tasks = 2 completed_tasks = 0 while completed_tasks < total_tasks: try: # 阻塞等待队列中的任务,降低CPU占用 callback = callback_queue.get(block=True) callback() completed_tasks += 1 print("After callback") except queue.Empty: pass # 最终确保所有Matplotlib资源被清理 plt.close('all')
额外优化建议
如果上述修改后仍有问题,可以尝试切换Matplotlib后端:
在代码开头添加以下语句(需要确保系统已安装Tkinter):
plt.switch_backend('TkAgg')
MacOSX后端在某些场景下的GUI生命周期管理存在兼容性问题,切换到TkAgg或QtAgg后端可能解决卡顿问题。
内容的提问来源于stack exchange,提问作者frank b.
相关产品推荐
相关产品推荐

