Python Matplotlib图挂起在线程中。使用Thread.join()
考虑下面的例子Python Matplotlib图挂起在线程中。使用Thread.join(),python,multithreading,matplotlib,Python,Multithreading,Matplotlib,考虑下面的例子 from time import sleep import matplotlib.pyplot as plt from threading import Thread import numpy as np class Monitor(Thread): def __init__(self): Thread.__init__(self) _, self.ax = plt.subplots() self.data = []
from time import sleep
import matplotlib.pyplot as plt
from threading import Thread
import numpy as np
class Monitor(Thread):
def __init__(self):
Thread.__init__(self)
_, self.ax = plt.subplots()
self.data = []
def add_point(self, pt):
self.data.append(pt)
self.ax.cla()
self.ax.plot(self.data)
plt.draw()
class Main_job(Thread):
def __init__(self, monitor):
Thread.__init__(self)
self.monitor = monitor
self.output = []
def run(self):
for i in range(20):
print(i)
pt = np.random.rand()
self.output.append(pt)
self.monitor.add_point(pt)
sleep(1)
monitor = Monitor()
monitor.start()
main = Main_job(monitor)
main.start()
我有一个执行长时间操作的Main_作业
线程,我想监控它的运行时间
一、 因此,为matplotlib
图形定义了一个线程
,为我的进程定义了另一个线程
代码运行良好
假设现在我想在关闭程序之前对Main_job
线程的输出执行一些操作(例如打印或保存到文件)
我在代码末尾添加了以下几行
main.join()
print(main.output)
但是,这会以某种方式干扰matplotlib
,尽管未对monitor
线程进行任何修改,但该线程现在将挂起,直到main
完成
如何才能等待main
完成,同时避免monitor
挂起
编辑1-单线程(非工作)版本
在FiddleStix请求之后,这里是代码的单线程版本。尽管要简单得多,但在这个版本中,图形挂起,仅在流程结束时显示
from time import sleep
import matplotlib.pyplot as plt
import numpy as np
_, ax = plt.subplots()
output = []
for i in range(20):
print(i)
pt = np.random.rand()
output.append(pt)
ax.cla()
ax.plot(output)
sleep(1)
在绘图后添加plt.pause(0.01)
可以稍微改善这种情况。然而,通过这种方式显示图形,但用户只能在0.01秒内进行交互
注意:我知道用
plt.pause(1)
替换sleep(1)
可以解决这个问题,但是这里sleep
只是真实代码中一个长时间耗时操作的代理,而不仅仅是一个暂停。我想让监视器线程成为守护进程
线程()。如果主线程停止,守护进程线程将自动退出。这样,您就可以在后台运行某些东西,而无需显式停止第二个线程
只需添加一个类参数,即可将线程声明为守护进程:
class Monitor(Thread):
daemon = True
应该在主线程中运行。在单独的线程中运行作业,这样它就不会阻塞GUI
通过在线程中使用执行重画,可以在输出
更改时实现绘图的简单动画
请考虑使用用于实时情节的平滑动画
from time import sleep
import matplotlib.pyplot as plt
from threading import Thread
import numpy as np
_, ax = plt.subplots()
output = []
class Job(Thread):
def run(self):
for i in range(10):
print(i)
pt = np.random.rand()
output.append(pt)
sleep(1)
ax.cla()
ax.plot(output)
plt.draw()
job = Job()
job.start()
plt.show()
除非没有显示更多的代码,否则我看不到从主任务线程调用add_point的任何意义。Main_job.run()将等待add_point以同步方式返回,因此它不会为您带来任何好处。另外,我不确定Matplotlib是否是线程安全的。另外,您的Monitor类没有run方法,所以我认为它除了等待调用add_point之外,不会执行任何操作。如果是单线程的话,整个过程会简单得多,bug也会少一些。代码最初是单线程的,但是
matplotlib
在执行过程中挂起。我发现避免这种情况的唯一方法是将matplotlib
放在一个单独的线程中。如果你能想出一个更简单的版本,其中matplotlib
不挂起,并且不需要线程化
,我很乐意接受答案如果你发布挂起的单线程代码(在这里或在一个新问题中),那么我相信我们中的一个人将能够解决根本问题。如果有足够的代码来实际运行它(即使它被简化),那就更好了。编辑:哦,请告诉我们这是在笔记本中还是在普通的python脚本中。普通的python脚本MatPlotLib不是线程安全的,GUI必须在主线程中运行。考虑在MaMattLIB中使用动画中的任何一个工作解决方案。是否需要在主线类中保留MIN作业,或者可以/是否应该将它移动到主线程?您可以将其移动到主线程。只有在计算过程中需要额外的用户/编程交互时,将其分开才有用对不起,回复太晚了。然而,这根本不起作用。只需将daemon=True
添加到上面的代码(包括main.join()
)matplotlib保持挂起状态,并且图形仅显示在末尾,很抱歉,但是发布的代码不起作用。如果将print(output)
放在代码末尾,则会立即执行(因为我们没有job.join()
这是预期的),只打印[]
。相反,如果我们添加job.join();打印(输出)
输出正确显示在末尾,但图形与现在完全一样挂起。我将尝试使用动画API查看它是否工作。PS:很抱歉回复太晚我的回复地址由于正在运行的后台作业而阻止了主线程呈现图表。您可以在后台作业运行函数的末尾声明对输出的操作