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

Matplotlib运行多进程时plt.pause报错、无绘图输出问题

Matplotlib多线程运行正常、多进程模式失效问题说明

问题复现

最初多线程实现

最初使用Python threading 多线程实现Matplotlib实时绘图的代码如下:

class Viewer:
    def __init__(self):
        _, self.ax = plt.subplots(1, 1)
        self.ax.set_ylim((-self.ax_lim, self.ax_lim))
        self.ax.set_xlim((-self.ax_lim, self.ax_lim))
        self.ax.set_aspect('equal')
        self.ax.grid()
        self.textvar = self.ax.text(-self.ax_lim-10, -self.ax_lim-10, '0.0')
        
        self.i=0

        # 多线程部分
        x = threading.Thread(target=self.thread_function, args=(1,))
        x.start()
        plt.show()

    def thread_function(self,name):
        while(self.i<5000):
            # 执行绘图操作
            self.i+=1
            #plt.pause(0.01) 
            # 省略具体绘图逻辑

运行该脚本可正常弹出Matplotlib绘图窗口,内容支持实时刷新,但受Python GIL机制限制,多线程模式运行速度极慢。

多进程改造后的异常

参考多线程性能瓶颈的相关说明,改用multiprocessing多进程实现,代码如下:

from multiprocessing import Process    
class Viewer:
    def __init__(self):
        _, self.ax = plt.subplots(1, 1)
        self.ax.set_ylim((-self.ax_lim, self.ax_lim))
        self.ax.set_xlim((-self.ax_lim, self.ax_lim))
        self.ax.set_aspect('equal')
        self.ax.grid()
        self.textvar = self.ax.text(-self.ax_lim-10, -self.ax_lim-10, '0.0')

        self.i=0

        # 多进程部分
        x=Process(target=self.thread_function,args=(1,))
        x.start()
        plt.show()

    def thread_function(self,name):
        while(self.i<5000):
            # 执行绘图操作
            self.i+=1
            #plt.pause(0.01) ##<--- 此处调用会触发错误
            time.sleep(0.01)
            # 省略具体绘图逻辑

改造后运行出现两类异常:

  1. 子进程调用plt.pause时触发XCB相关X服务报错,程序直接崩溃,错误信息如下:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:259: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":1"
after 348 requests (348 known processed) with 0 events remaining.
Aborted (core dumped)
  1. 将plt.pause替换为time.sleep(0.01)后无报错,但Matplotlib窗口无任何绘图内容渲染输出。

根本原因

两种模式表现差异的核心逻辑如下:

  • 多线程模式可正常运行的原因:多线程属于同一进程,所有线程共享进程内存空间,Matplotlib创建的画布、坐标轴等对象在所有线程中指向同一块内存地址。plt.show()启动的GUI主事件循环可以正常读取到子线程对绘图对象的修改,因此可以正常刷新渲染,仅因为GIL的存在,CPU密集型任务无法并行,导致运行速度慢。
  • 多进程模式无渲染输出的原因:多进程间内存是完全隔离的,Process启动子进程时,子进程拿到的是主进程所有对象的拷贝副本,而非原对象。子进程中对self.ax、self.i等属性的修改,全部作用在子进程独立内存的副本上,主进程中运行GUI事件循环的Matplotlib实例收不到任何修改信号,自然不会有内容更新。
  • 多进程模式XCB报错的原因:Linux下X11 GUI服务的连接与创建它的进程绑定,子进程中调用plt.pause时,子进程内的Matplotlib副本会尝试直接和X Server通信,跨进程发起GUI请求未做线程安全初始化(即报错中提到的未调用XInitThreads),会直接触发XCB事件队列校验失败,导致程序崩溃。

正确实现方案

  • 所有Matplotlib绘图、刷新操作必须放在运行GUI事件循环的主进程中执行,禁止子进程直接操作Matplotlib对象
  • 多进程仅负责运行计算密集型的业务逻辑,计算完成的结果通过进程间通信方式(如multiprocessing.Queue、Pipe)传回主进程
  • 主进程可通过Matplotlib自带的定时器(canvas.new_timer)定期从通信队列读取新数据,更新绘图元素后触发画布刷新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:36:24