sách gpt4 ăn đã đi

python - Matplotlib 和多处理 RuntimeError

In lại 作者:太空狗 更新时间:2023-10-30 02:32:53 28 4
mua khóa gpt4 giày nike

我正在尝试同时使用多处理和 matplotlib。

我正在创建一个标准的 Pool,添加与 apply_async 的工作,并使用 apply_async 的回调函数更新 GUI,它运行于Pool 的父进程(我用 os.getpid() 验证了这一点)。示例:

from pylab import *
from numpy import *
from numpy.random import random
from multiprocessing import Pool

# Output image
global out_all
out_all = zeros((256, 256))

# Only does something to in_image, doesn't access anything else
def do_work(in_image):
for x in xrange(100000):
out_image = in_image[::-1, ::-1]
return out_image

# Update the output image and display if needed
def do_update(out_image):
global out_all
print ("Updating")
out_all += out_image
clf()
imshow(out_all)
trình diễn()

# Input images (close enough to what I do as well)
work = [random((256, 256)) for f in range(20)]

# Don't block when showing something
ion()

# Do the work
print "Starting pool"
pool = Pool()
for o in work:
pool.apply_async(do_work, [o], callback=do_update).get()
pool.close()
pool.join()
print "Stopping pool"

# Block
ioff()
trình diễn()
print "Done"

处理本身工作正常,进程确实在 pool.join() 上被破坏了,但是 Matplotlib(和 TK,我猜)在我之后尝试做某事时立即提示,即使只是退出程序:

Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
File "test_thread.py", line 27, in
trình diễn()
File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 139, in show
_show(*args, **kw)
File "/usr/lib/pymodules/python2.7/matplotlib/backend_bases.py", line 83, in __call__
manager.show()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 444, in show
self.canvas.draw_idle()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 258, in draw_idle
self._idle_callback = self._tkcanvas.after_idle(idle_draw)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 512, in after_idle
return self.after('idle', func, *args)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 504, in after
name = self._register(callit)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1101, in _register
self.tk.createcommand(name, f)
RuntimeError: main thread is not in main loop
Error in atexit._run_exitfuncs:
Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
File "/usr/lib/python2.7/atexit.py", line 24, in _run_exitfuncs
func(*targs, **kargs)
File "/usr/lib/pymodules/python2.7/matplotlib/_pylab_helpers.py", line 82, in destroy_all
manager.destroy()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 452, in destroy
self.canvas._tkcanvas.after_cancel(self.canvas._idle_callback)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 519, in after_cancel
data = self.tk.call('after', 'info', id)
RuntimeError: main thread is not in main loop
Error in sys.exitfunc:
Theo dõi (cuộc gọi gần đây nhất là cuộc gọi cuối cùng):
File "/usr/lib/python2.7/atexit.py", line 24, in _run_exitfuncs
func(*targs, **kargs)
File "/usr/lib/pymodules/python2.7/matplotlib/_pylab_helpers.py", line 82, in destroy_all
manager.destroy()
File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 452, in destroy
self.canvas._tkcanvas.after_cancel(self.canvas._idle_callback)
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 519, in after_cancel
data = self.tk.call('after', 'info', id)
RuntimeError: main thread is not in main loop

我的第一个想法是 TK 上下文在每个 fork() 上都是重复的,这以某种方式干扰了主进程中的 TK 循环,但我在我的程序中没有做任何与 TK 相关的事情 worker 。有什么想法吗?

câu trả lời hay nhất

错误消息引用 Tkinter .所以看起来你正在使用 TkAgg 后端。下面的代码是特定于 TkAgg/Tkinter 的。特别是电话

win.after(100, animate)

使用 Tkinter 特定的 sau đó方法。对 GtkAgg/PyGtk 有类似的调用,对其他后端也有类似的调用。但我只想强调以下内容是 TkAgg/Tkinter 特定的。


Tkinter 旨在在单线程中运行。也就是说,所有 Tkinter GUI 调用都应源自单个线程(通常,不一定是主线程)。

游泳池的 apply_async回调方法在主进程中的单独 ( _handle_results) 线程中运行。自 imshow()从 Pool 的 _handle_results 调用线程和trình diễn()在主线程中被调用,Tkinter提示

RuntimeError: main thread is not in main loop

我看不到使用 apply_async 的方法在这种情况下回调。

相反,我们可以安排 do_workout_imagehiện hữumultiprocessing.Queue() (我在下面的代码中称之为 out_queue)。然后,我们将让主进程的主线程轮询此队列以查找项,并在它们从队列中出来时显示它们。此轮询在 animate 中完成函数,如下。


plt.ion()仅适用于交互式 session 。虽然有时可以编写一些似乎可以与 plt.ion() 一起使用的小脚本。 ,如果您拒绝使用 plt.ion(),您将获得更好的结果和更清晰的 GUI在脚本中,而是编写符合 GUI 框架事件循环的代码。

尽管修复脚本并使用 plt.ion() 可能是可能的,因为这不是编写 matplotlib 脚本的推荐方式,让我们看看是否可以避免这样做。


plt.hiển thị()告诉 Tkinter 运行它的事件循环。请注意,一旦进行此调用,就会绘制 GUI 窗口,您可以单击按钮、放大和缩小等。

我们需要以某种方式向这个事件循环中注入(inject)一个函数,由事件循环定期运行,并与可能发生的所有其他 GUI 事件协作。我们希望此函数检查是否有任何工作子进程为我们提供输出,如果有,则更新 imshow 图像。

用TkAgg/Tkinter,注入(inject)这样一个函数的方式是

win = fig.canvas.manager.window
win.after(100, animate)

这将告诉 Tkinter 运行函数 animate (一次)在(大约)100 毫秒过去后。因为我们想要函数 animate要定期运行,我们只需坚持另一个

win.after(100, animate)

hiện hữu animate 末尾调用.


import matplotlib as mpl
mpl.use('TkAgg')
nhập matplotlib.pyplot dưới dạng plt
nhập numpy dưới dạng np
import multiprocessing as mp
import logging
import Queue
logger = mp.log_to_stderr(logging.INFO)

# Only does something to in_image, doesn't access anything else
def do_work(in_image):
logger.info('Processing in_image')
for x in xrange(100000):
out_image = in_image[::-1, ::-1]
out_queue.put(out_image)

# Update the output image and display if needed
out_all = np.zeros((256, 256))


def pool_initializer(out_queue_):
# Setup out_queue as a global variable *in the worker subprocesses*
global out_queue
out_queue = out_queue_


def animate():
global out_all
thử:
out_image = out_queue.get_nowait()
except Queue.Empty:
vượt qua
khác:
logger.info("Updating")
out_all += out_image
im.set_data(out_all)
fig.canvas.draw() # redraw the canvas
win.after(100, animate)

nếu __name__ == '__main__':
out_queue = mp.Queue()
logger.info("Starting pool")
pool = mp.Pool(initializer=pool_initializer, initargs=(out_queue, ))
work = [np.random.random((256, 256)) for f in range(20)]
for o in work:
pool.apply_async(do_work, [o])
pool.close()

fig, ax = plt.subplots()
win = fig.canvas.manager.window
# Output image
im = plt.imshow(out_all, vmin=0, vmax=1)

# Register a function to be run once
win.after(100, animate)
plt.hiển thị()
logger.info("Done")

关于python - Matplotlib 和多处理 RuntimeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16016102/

28 4 0
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress