繁体   English   中英

多处理和 matlibplot,非阻塞图

[英]Multiprocessing and matlibplot, non-blocking plots

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

我想做什么:

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

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

此代码是在关闭主进程时Python close children修改的

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

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

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

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

不能保证在调用 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)

我推荐来自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())
 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM