I\'m actually finding it hard to believe that I\'ve run into the issue I have, it seems like it would be a big bug in the python multiprocessing module... Anyways the proble
When you call apply_async it returns a AsyncResult object and leaves the workload distribution to a separate thread (see also this answer). This thread encounters the problem that the Queue object can't be pickled and therefore the requested work can't be distributed (and eventually executed). We can see this by calling AsyncResult.get:
r = p.apply_async(f,args=(q,))
r.get()
which raises a RuntimeError
:
RuntimeError: Queue objects should only be shared between processes through inheritance
However this RuntimeError
is only raised in the main thread once you request the result because it actually occurred in a different thread (and thus needs a way to be transmitted).
So what happens when you do
p.apply_async(f,args=(q,))
is that the target function f
is never invoked because one of it's arguments (q
) can't be pickled. Therefore q
never receives an item and remains empty and for that reason the call to q.get
in the main thread blocks forever.
With apply_async
you don't have to manage the result queues manually but they are readily provided to you in form of AsyncResult objects. So you can modify the code to simply return from the target function:
from multiprocessing import Queue, Pool
def f():
return [42, None, 'hello']
if __name__ == '__main__':
q = Queue()
p = Pool(1)
result = p.apply_async(f)
print(result.get())