Python - 从 mpl_connect 处理程序调用时 ProcessPoolExecutor 挂起

Python - ProcessPoolExecutor hangs when called from a mpl_connect handler

我正在使用并行处理来生成使用复数的函数图。我的脚本允许您使用标准 matplotlib 控件放大绘图区域,然后在新限制内重新生成绘图以提高分辨率。

这是我第一次涉足并行处理,据我所知,我需要以 if __name__ == __main__: 作为序言,以便正确导入模块。当 运行 我的脚本时,第一个图已成功生成并按预期显示。但是,当从我的事件处理程序再次调用绘图函数时,它会无限期地挂起。我假设挂起是由一些与要求 if __name__ == __main__: 类似的问题引起的,因为并行进程是从脚本主体外部产生的,但我还没有想出比这更进一步的东西。

import numpy as np
import matplotlib.pyplot as plt
from concurrent.futures import ProcessPoolExecutor
import multiprocessing

res = [1000, 1000]
base_factor = 2.
cpuNum = multiprocessing.cpu_count()

def brot(c, depth=200):
    z = complex(0)

    for i in range(depth):
        z = pow(z, 2) + c

        if abs(z) > 2:
            return i

    return -1

def brot_gen(span):
    re_span = span[0]
    im_span = span[1]

    mset = np.zeros([len(im_span), len(re_span)])

    for re in range(len(re_span)):
        for im in range(len(im_span)):
            mset[im][re] = brot(complex(re_span[re], im_span[im]))

    return mset

def brot_gen_parallel(re_lim, im_lim):
    re_span = np.linspace(re_lim[0], re_lim[1], res[0])
    im_span = np.linspace(im_lim[0], im_lim[1], res[1])

    split_re_span = np.array_split(re_span, cpuNum)

    packages = [(sec, im_span) for sec in split_re_span]
    print("Generating set between", re_lim, "and", im_lim, "...")

    with ProcessPoolExecutor(max_workers = cpuNum) as executor:
            result = executor.map(brot_gen, packages)

    mset = np.concatenate(list(result), axis=1)
    print("Set generated")

    return mset

def handler(ax):
    def action(event):
        if event.button == 2:
            cur_re_lim = ax.get_xlim()
            cur_im_lim = ax.get_ylim()

            mset = brot_gen_parallel(cur_re_lim, cur_im_lim)

            ax.cla()
            ax.imshow(mset, extent=[cur_re_lim[0], cur_re_lim[1], cur_im_lim[0], cur_im_lim[1]], origin="lower", vmin=0, vmax=200, interpolation="bilinear")

            plt.draw()

    fig = ax.get_figure()
    fig.canvas.mpl_connect('button_release_event', action)

    return action

if __name__ == "__main__":
    re_lim = np.array([-2.5, 2.5])
    im_lim = res[1]/res[0] * re_lim

    mset = brot_gen_parallel(re_lim, im_lim)

    plt.imshow(mset, extent=[re_lim[0], re_lim[1], im_lim[0], im_lim[1]], origin="lower", vmin=0, vmax=200, interpolation="bilinear")

    ax = plt.gca()

    f = handler(ax)

    plt.show()

编辑:我想知道代码中是否存在导致异常的错误,但是这可能没有成功传回控制台,但是我通过 运行 相同的任务测试了这个没有拆分它进入并行任务并成功完成。

我找到了我自己问题的答案。答案就在我使用的 IDE 中。根据我的经验,在大多数 IDE 中,默认情况下 plt.show() 会阻止执行,但是在 Spyder 中,默认值似乎等同于 plt.show(block=False),这意味着脚本已完成,因此需要执行任何操作成功启动并行进程不再可用,导致挂起。只需将语句更改为 plt.show(block=True) 即可解决此问题,这意味着脚本仍然有效。

我对并行处理仍然很陌生,所以我对任何人可以提供的任何更多信息非常感兴趣,因为缺少什么可以阻止并行处理工作。