I'm trying to use multiprocessing and matplotlib together.
I'm creating a standard Pool, adding work with apply_async and updating the GUI with apply_async's callback function, which runs on the Pool's parent process (I verified this with os.getpid()). Example :
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)
show()
# 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()
show()
print "Done"
The processing itself works fine, the processes are really destroyed on pool.join(), but Matplotlib (and TK, I guess) complain as soon as I try to do something afterwards, even only exiting the program :
Traceback (most recent call last):
File "test_thread.py", line 27, in <module>
show()
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:
Traceback (most recent call last):
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:
Traceback (most recent call last):
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
My first thought was that the TK context was duplicated on each fork(), which somehow interferred with the TK loop in the main process, but I'm not doing anything TK-related in my workers. Any ideas?