matplotlib show 挂起线程

matplotlib show hangs the thread

我有两个通过套接字进行通信的进程。 第一个进程先打开第二个进程,方法如下:

def run_command(cmd)
    subprocess.call(cmd, shell=True)

cmd = 'python full_path_to_script.py'
thread = Thread(target=run_command, args=(cmd,)
thread.start()

然后打开连接:

from multiprocessing.connection import Client
address = ('localhost', port_number)
conn = Client(address, authkey=b'some_password')

当第一个想要绘制一些东西时,它会向第二个发送一条消息,第二个会破译消息并使用 matplotlib 绘制数据。这个想法是第一条消息打开一个图像,其他消息发送更新图像。 问题是 pyplot.show 挂起现在无法获取新消息的第二个进程。我尝试使用 pyplot.ion() 但后来这个数字被冻结了(添加 pyplot.pause(0.001) 没有帮助)。

如果不看代码,很难准确判断您在做什么,但我认为这是预期的正确行为。

如果您在没有交互模式的情况下使用 plt.show,则发生的情况是 GUI 事件循环正在控制您的子进程中的线程。这个事件循环是接收 mouse/keyboard 事件来使图形交互的。因此,只要 window 打开,GUI 就会控制你的第二个进程的主线程,它似乎会忽略你的其他消息。

或者,当您使用 plt.ion() 时,GUI 事件循环不会 运行,而是依靠其他东西定期启动它(在命令提示符下,这是通过 PyOS_InputHook 机制)所以虽然你的第二个进程正在获取你的消息,但没有显示任何内容(因为 GUI 事件循环没有 运行 重新绘制 window)并且 window 似乎已经死了(因为事件循环不消耗输入事件)。

您要么需要在第二个过程中滚动您自己的事件循环(因为您正在实施 RPC,这不是一个坏主意)并定期调用 canvas.flush_events(这将 运行 事件循环直到所有未决事件都已用完),让 GUI 框架处理从引导进程获取事件,然后(可能)将跟随进程上的消息处理推送到子线程(如果这样做,请非常小心,只使用 draw_idle 请求重新绘制图形,GUI 不喜欢您尝试从非主线程绘制)。

我使用 pyqtgraph 库连续绘制从 Windows 下的 COM 端口 运行 接收到的值,因为我永远无法 matplotlib 可靠地更新实时尽管数小时的尝试。 pyqtgraph 附带了一个很好的示例文件,我将其用作模板,然后可以针对我的用例进行修改,经过几次尝试后我就可以可靠地工作了。

所以我

  • 一个 python 线程在 while 循环中读取 COM 端口,该线程在一端填充 deque 并在另一端弹出一个元素。
  • 然后在图形更新函数中每 20 毫秒左右将双端队列复制到图形中。