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)
即可解决此问题,这意味着脚本仍然有效。
我对并行处理仍然很陌生,所以我对任何人可以提供的任何更多信息非常感兴趣,因为缺少什么可以阻止并行处理工作。
我正在使用并行处理来生成使用复数的函数图。我的脚本允许您使用标准 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)
即可解决此问题,这意味着脚本仍然有效。
我对并行处理仍然很陌生,所以我对任何人可以提供的任何更多信息非常感兴趣,因为缺少什么可以阻止并行处理工作。