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

标签 python concurrent.futures

我正在使用并行处理来生成使用复数的函数图。我的脚本允许您使用标准 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) 即可解决此问题,这意味着脚本仍然有效。

我对并行处理还很陌生,因此我对任何人都可以提供的有关阻止并行处理工作所缺少的内容的更多信息非常感兴趣。

关于Python - 从 mpl_connect 处理程序调用时 ProcessPoolExecutor 挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60427864/

相关文章:

python - 如何选择txt文件中的某个字符串并将其列出在csv文件中?

python - 从具有相同名称但文件类型不同的其他文件中查找一个没有扩展名的文件

python - 确保ROI裁剪坐标(x,y,w,h)有效且在Python OpenCV的范围内

python - 我可以在 Future 中使用 ProcessPoolExecutor 吗?

python - Flask - 作业不作为后台进程运行

java - 缓存线程池无限增长

python - APScheduler 关闭后无法安排新的 future

python - 使用多维数组中的每个第一个元素

python - 将 UTC 时间戳转换为正常日期和时间

Python 线程池——创建子任务并等待它们的任务