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

多线程场景下Matplotlib关闭后图形窗口卡顿无法消失的解决咨询

解决Matplotlib多线程提交任务后第二个窗口无法正常关闭的问题

问题分析

你的代码在MacOS环境下出现第二个绘图窗口关闭卡顿的问题,核心原因有三点:

  1. 每次绘图任务重复导入matplotlib.pyplot,导致Matplotlib内部状态混乱;
  2. 绘图完成后未主动清理窗口资源,MacOSX后端的GUI残留无法正常回收;
  3. 主线程的无限空轮询占用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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:55:09