多处理和matlibplot,非阻塞图

时间:2014-01-15 02:21:36

标签: python matplotlib multiprocessing background-process

我知道关于这个主题还有很多其他问题,我已经阅读/试验过这些解决方案,但是没有一个能完全符合我的要求或者没有工作......

我想做什么:

我想使用matplotlib创建一个绘图,在新进程中启动该绘图,使其在主线程运行时打开并响应,此外当主线程退出时不会杀死子进程。如果可能的话,我想要一些便携的东西因此我避免使用叉子,因为我的印象是它不是(正确吗?)。我在matplotlib中尝试过show(block = False)。如果没有其他任何事情我很乐意接受,但最好主要线程退出并且情节仍然坐在那里。

到目前为止我最好的尝试:

此代码已从Python close children when closing main process

修改
import logging, signal, sys, time
import multiprocessing as mp 
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid.axislines import SubplotZero

class AddProcessNameFilter(logging.Filter):
    """Add missing on Python 2.4 `record.processName` attribute."""
    def filter(self, r):
        r.processName = getattr(r, 'processName', mp.current_process().name)
        return logging.Filter.filter(self, r)

def print_dot(plt):
    signal.signal(signal.SIGTERM, signal.SIG_IGN)
    while True:
        mp.get_logger().info(".")
        plt.show(block=True)

def main():
    logger = mp.log_to_stderr()
    logger.setLevel(logging.INFO)
    logger.addFilter(AddProcessNameFilter()) # fix logging records

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot([0, 1, 2, 3], [1, 1, 3, 2],'ro')

    # create daemonic child processes
    p = mp.Process(target=print_dot, args=(plt,))
    p.daemon = True
    p.start()    

if __name__=="__main__":
    mp.freeze_support()
    main()

此代码会发生什么......

剧情未启动另外主线程不退出它只是等待连接。中断时我也会收到以下错误......

X Error of failed request:  BadIDChoice (invalid resource ID chosen for this connection)
  Major opcode of failed request:  53 (X_CreatePixmap)
  Resource id in failed request:  0x4400017
  Serial number of failed request:  344
  Current serial number in output stream:  352

不确定该怎么做。有任何想法吗? 提前致谢:D

PS:Ubuntu 12.04 ......但我不知道在这种情况下这是否特别相关...

2 个答案:

答案 0 :(得分:0)

我使用以下代码。它类似于你的,但加入旧进程,因为该函数应该被多次调用。您可以关闭主要流程,但不会关闭该地块。

无法保证在调用p.start之后将显示该图。但这很不寻常,只发生在我身上几次。在这些时候,如果再次调用plot或者调用p.is_alive(),则会显示窗口。

    import multiprocessing as mp
    import sys
    def foo(*arg):
        import matplotlib.pyplot as plt
        plt.ioff()    
        plt.plot(*arg)
        plt.show()

    if __name__ == '__main__':
        mp.freeze_support()
        arg=(range(10),)
        global pl

        #create the process list, if it does not exists
        try:
            pl
        except NameError:
            pl = []    

        #Join old ones to keep zombie process list small
        for i in range(len(pl)):
            if not (pl[i] is None):
                if not pl[i].is_alive():
                    pl.pop(i).join()


        #create plot process
        p = mp.Process(target=foo, args=arg)
        p.start()
        pl.append(p)

答案 1 :(得分:0)

我推荐https://stackoverflow.com/a/62354049/13995577的解决方案。对我来说效果很好。虽然有点小,但相对较小。

import multiprocessing as mp
def my_plot_routine(q):
    ...
    q.put('Done, see plot window')
    plt.show()
    return

class EverLastingProcess(mp.Process):
    def join(self, *args, **kwargs):
        pass

    def __del__(self):
        pass

if __name__ == '__main__':
    # create plot process
    mp.set_start_method('spawn')
    q = mp.Queue()
    p = EverLastingProcess(target=my_plot_routine, args=(q,))
    p.start()
    print(q.get())