使用多进程时Matplotlib图形无响应
我正在尝试创建一个非常简单的应用程序,目的是从一个实时数据源更新matplotlib中的图表。数据是在一个单独的进程中接收的。但是,我的matplotlib图形总是崩溃,即使是最基本的显示也不行。matplotlib窗口失去了互动性,变成了"图形 1(未响应)"。我是否需要明确给matplotlib一些CPU时间,以便它能和multiprocessing
正常工作呢?
这里有一个基本的示例,在Windows 7、64位、Python 2.7.3 32位的几乎所有后端上都崩溃。我使用的是从这里下载的scipy-stack的非官方版本:
编辑:在Ubuntu(32位)上似乎也不工作。
import time
from multiprocessing import Process
import matplotlib.pyplot as plt
def p1_func():
while True:
time.sleep(1)
def p2_func():
plt.ion()
plt.plot([1.6, 2.7])
while True:
time.sleep(1)
if __name__ == '__main__':
p1_proc = Process(target=p1_func)
p2_proc = Process(target=p2_func)
p1_proc.start()
p2_proc.start()
p1_proc.join()
p2_proc.join()
我到底哪里做错了?
一般来说,如何让matplotlib的实时数据交互图表和线程(无论是多进程还是其他方式)共存呢?
4 个回答
0
join()
是在等着某个进程完成。在这个例子里,代码在等一个无限循环的进程完成 :)
接着 @tcaswell 的评论,混合使用图形界面循环和多进程的东西是有风险的。先试试这个,而不是上面的 join
代码:
procs = [p1_proc, p2_proc]
while any( (p.is_alive() for p in procs) ):
time.sleep(1)
1
你也可以使用线程来处理这个问题,我用pylab来绘图。
import pylab
from threading import Thread
def threaded_function(arg):
pylab.plot(range(1,10))
pylab.show(block=True)
if __name__ == "__main__":
thread = Thread(target = threaded_function, args = (10, ))
thread.start()
thread.join()
print("thread finished...exiting")
3
我在使用 matplotlib.animation
和 multiprocessing.Pool
的时候遇到了一些问题(程序会悄悄崩溃),后来我按照 @deinonychusaur 的建议解决了这个问题,也就是使用一个非交互式的后端。
在你的导入部分加上这个:
import matplotlib
matplotlib.use('AGG') # Do this BEFORE importing matplotlib.pyplot
import matplotlib.pyplot as plt
想了解后端的相关信息,可以查看这里: http://matplotlib.org/faq/usage_faq.html#what-is-a-backend
3
下面是一个简单的例子
import time
from multiprocessing import Process, Pipe
import numpy as np
import matplotlib.pyplot as plt
class DataStreamProcess(Process):
def __init__(self, connec, *args, **kwargs):
self.connec = connec
Process.__init__(self, *args, **kwargs)
def run(self):
random_gen = np.random.mtrand.RandomState(seed=127260)
for _ in range(30):
time.sleep(0.01)
new_pt = random_gen.uniform(-1., 1., size=2)
self.connec.send(new_pt)
def main():
conn1, conn2 = Pipe()
data_stream = DataStreamProcess(conn1)
data_stream.start()
plt.gca().set_xlim([-1, 1.])
plt.gca().set_ylim([-1, 1.])
plt.gca().set_title("Running...")
plt.ion()
pt = None
while True:
if not(conn2.poll(0.1)):
if not(data_stream.is_alive()):
break
else:
continue
new_pt = conn2.recv()
if pt is not None:
plt.plot([pt[0], new_pt[0]], [pt[1], new_pt[1]], "bs:")
plt.pause(0.001)
pt = new_pt
plt.gca().set_title("Terminated.")
plt.draw()
plt.show(block=True)
if __name__ == '__main__':
main()