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

Python多进程问题:持续打印数据+可重开Matplotlib图表时进程重启报错

解决多进程重启Matplotlib图表的问题

为啥会报错?

Python里的multiprocessing.Process对象是“一次性”的——只要你调用过它的start()方法,哪怕这个进程已经跑完或者被关掉了,都不能再调用start()启动它第二次,这就是你碰到AssertionError: cannot start a process twice的原因。

怎么改?每次重启都建新进程

别抱着同一个Process对象反复用,用户每次输入'y'要重启图表时,就重新创建一个新的Process实例再启动就行。另外还要注意Matplotlib在多进程里的用法:子进程里得单独初始化绘图后端,别和主进程的绘图环境搅在一起。

修正后的示例代码

import multiprocessing
import time
import matplotlib.pyplot as plt
import numpy as np
import sys
import select

# 模拟实时生成数据
def generate_data():
    while True:
        yield np.random.randn()
        time.sleep(0.5)

# 子进程负责绘图的函数
def plot_data(data_queue):
    # 子进程单独设置Matplotlib后端,避免和主进程冲突
    plt.switch_backend('TkAgg')  # 你也可以换成'Qt5Agg'之类的,看你环境支持哪个
    fig, ax = plt.subplots()
    line, = ax.plot([], [], 'r-')
    ax.set_ylim(-3, 3)
    ax.set_title('实时数据展示')
    
    data_history = []
    while True:
        try:
            # 从队列取数据,超时1秒避免卡死
            data = data_queue.get(timeout=1)
            data_history.append(data)
            line.set_data(range(len(data_history)), data_history)
            ax.relim()
            ax.autoscale_view()
            fig.canvas.draw_idle()
            plt.pause(0.01)
        except multiprocessing.queues.Empty:
            # 主进程挂了就退出子进程
            if not multiprocessing.parent_process().is_alive():
                break
        except:
            # 捕获关闭窗口的异常,直接退出子进程
            break

if __name__ == '__main__':
    data_queue = multiprocessing.Queue(maxsize=100)
    data_generator = generate_data()
    plot_process = None

    print("主窗口持续打印数据,输入'y'重启图表,输入'q'退出")
    while True:
        # 生成并打印数据
        data = next(data_generator)
        print(f"当前数据: {data:.2f}")
        # 把数据放进队列给绘图进程
        if not data_queue.full():
            data_queue.put(data)
        
        # 非阻塞处理用户输入,不打断数据打印
        if select.select([sys.stdin], [], [], 0.1)[0]:
            user_input = sys.stdin.readline().strip().lower()
            if user_input == 'q':
                # 退出前先关掉绘图进程
                if plot_process and plot_process.is_alive():
                    plot_process.terminate()
                    plot_process.join()
                break
            elif user_input == 'y':
                # 先关掉旧的绘图进程(如果还在跑)
                if plot_process and plot_process.is_alive():
                    plot_process.terminate()
                    plot_process.join()
                # 创建新的进程实例并启动
                plot_process = multiprocessing.Process(target=plot_data, args=(data_queue,))
                plot_process.start()

    print("程序退出")

几个要注意的点

  • 别复用Process对象:每次重启都新建一个Process,旧的用完就处理掉,别想着二次启动。
  • Matplotlib后端要隔离:子进程里单独调用plt.switch_backend(),不然容易和主进程的绘图环境冲突,导致各种奇怪问题。
  • 用队列传数据:主进程和子进程之间用multiprocessing.Queue传数据,这是多进程里安全共享数据的方式,比直接用全局变量靠谱。
  • 优雅收尾:重启或退出时,先终止旧进程并调用join()等它彻底结束,避免留下僵尸进程。

内容的提问来源于stack exchange,提问作者Paul K.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:56:22