考虑以下示例
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_job
线程,我想在运行时监视它。
I、 因此,为matplotlib
图形定义了一个Thread
,为我的过程定义了另一个。
代码运行良好
现在假设我想在关闭程序之前对Main_job
线程的输出进行一些处理(例如打印它或将它保存到文件中(。
我在我的代码的末尾添加了以下几行
main.join()
print(main.output)
然而,这在某种程度上干扰了matplotlib
,尽管根本没有修改monitor
线程,但它现在挂起,直到main
完成。
如何在等待main
完成的同时避免monitor
挂起?
EDIT 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
只是实际代码中长时间耗时操作的代理,而不仅仅是暂停。
我认为您希望使Monitor线程成为daemon
线程(文档(。如果主线程停止,守护进程线程将自动退出。通过这种方式,您可以在后台运行一些东西,而无需显式地停止第二个线程。
只需添加一个类参数即可将线程声明为守护进程:
class Monitor(Thread):
daemon = True
GUI主循环应该在主线程中运行。在单独的线程中运行作业,这样它就不会阻塞GUI。
通过在线程中使用matplotlib.pyplot.draw执行重绘,可以实现output
更改时绘图的简单动画。
请考虑使用动画API对现场情节进行平滑动画。
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()