Would it be possible to create a python Pool that is non-daemonic? I want a pool to be able to call a function that has another pool inside.
I want this because deamon processes cannot create process. Specifically, it will cause the error:
AssertionError: daemonic processes are not allowed to have children
For example, consider the scenario where function_a
has a pool which runs function_b
which has a pool which runs function_c
. This function chain will fail, because function_b
is being run in a daemon process, and daemon processes cannot create processes.
I had the necessity to employ a non-daemonic pool in Python 3.7 and ended up adapting the code posted in the accepted answer. Below there's the snippet that creates the non-daemonic pool:
As the current implementation of
multiprocessing
has been extensively refactored to be based on contexts, we need to provide aNoDaemonContext
class that has ourNoDaemonProcess
as attribute.MyPool
will then use that context instead of the default one.That said, I should warn that there are at least 2 caveats to this approach:
multiprocessing
package, and could therefore break at any time.multiprocessing
made it so hard to use non-daemonic processes, many of which are explained here. The most compelling in my opinion is:The
multiprocessing.pool.Pool
class creates the worker processes in its__init__
method, makes them daemonic and starts them, and it is not possible to re-set theirdaemon
attribute toFalse
before they are started (and afterwards it's not allowed anymore). But you can create your own sub-class ofmultiprocesing.pool.Pool
(multiprocessing.Pool
is just a wrapper function) and substitute your ownmultiprocessing.Process
sub-class, which is always non-daemonic, to be used for the worker processes.Here's a full example of how to do this. The important parts are the two classes
NoDaemonProcess
andMyPool
at the top and to callpool.close()
andpool.join()
on yourMyPool
instance at the end.The multiprocessing module has a nice interface to use pools with processes or threads. Depending on your current use case, you might consider using
multiprocessing.pool.ThreadPool
for your outer Pool, which will result in threads (that allow to spawn processes from within) as opposed to processes.It might be limited by the GIL, but in my particular case (I tested both), the startup time for the processes from the outer
Pool
as created here far outweighed the solution withThreadPool
.It's really easy to swap
Processes
forThreads
. Read more about how to use aThreadPool
solution here or here.The issue I encountered was in trying to import globals between modules, causing the ProcessPool() line to get evaluated multiple times.
globals.py
Then import safely from elsewhere in your code