¿Sería posible crear un grupo de Python que no sea demoníaco? Quiero que un grupo pueda llamar a una función que tenga otro grupo dentro.
Quiero esto porque los procesos deamon no pueden crear procesos. Específicamente, causará el error:
AssertionError: daemonic processes are not allowed to have children
Por ejemplo, considere el escenario donde function_a
tiene una piscina que se ejecuta y function_b
que tiene una piscina que se ejecuta function_c
. Esta cadena de funciones fallará porque function_b
se está ejecutando en un proceso demonio y los procesos demonio no pueden crear procesos.
I want a pool to be able to call a function that has another pool inside
y cómo eso interfiere con el hecho de que los trabajadores están demonizados.AssertionError: daemonic processes are not allowed to have children
Respuestas:
La
multiprocessing.pool.Pool
clase crea los procesos de trabajo en su__init__
método, los convierte en demoníacos y los inicia, y no es posible restablecer sudaemon
atributoFalse
antes de que se inicien (y luego ya no está permitido). Pero puede crear su propia subclase demultiprocesing.pool.Pool
(multiprocessing.Pool
es solo una función contenedora) y sustituir su propiamultiprocessing.Process
subclase, que siempre es no demoníaca, para usarla en los procesos de trabajo.Aquí hay un ejemplo completo de cómo hacer esto. Las partes importantes son las dos clases
NoDaemonProcess
yMyPool
en la parte superior y para llamarpool.close()
ypool.join()
en suMyPool
instancia al final.fuente
multiprocessing.freeze_support()
MyPool
lugar del predeterminadoPool
? En otras palabras, a cambio de la flexibilidad de iniciar procesos secundarios, ¿qué costos debo pagar? (Si no hubiera costos, presumiblemente el estándarPool
habría utilizado procesos no demoníacos).Pool
clase se ha refactorizado ampliamente, porProcess
lo que ya no es un atributo simple, sino un método, que devuelve la instancia de proceso que obtiene de un contexto . Intenté sobrescribir este método para devolver unaNoDaemonPool
instancia, pero esto da como resultado la excepciónAssertionError: daemonic processes are not allowed to have children
cuando se usa el Pool.Tuve la necesidad de emplear un grupo no demoníaco en Python 3.7 y terminé adaptando el código publicado en la respuesta aceptada. A continuación, se muestra el fragmento que crea el grupo no demoníaco:
Como la implementación actual de
multiprocessing
se ha refactorizado extensamente para basarse en contextos, debemos proporcionar unaNoDaemonContext
clase que tenga nuestroNoDaemonProcess
atributo como.MyPool
luego usará ese contexto en lugar del predeterminado.Dicho esto, debo advertir que hay al menos 2 advertencias para este enfoque:
multiprocessing
paquete y, por lo tanto, podría romperse en cualquier momento.multiprocessing
es tan difícil usar procesos no demoníacos, muchos de los cuales se explican aquí . El más convincente en mi opinión es:fuente
AttributeError: module 'multiprocessing' has no attribute 'pool'
en Python 3.8.0import multiprocessing.pool
El módulo de multiprocesamiento tiene una interfaz agradable para usar grupos con procesos o subprocesos. Dependiendo de su caso de uso actual, podría considerar usar
multiprocessing.pool.ThreadPool
para su Pool externo, lo que dará como resultado subprocesos (que permiten generar procesos desde adentro) en lugar de procesos.Puede que esté limitado por el GIL, pero en mi caso particular (probé ambos) , el tiempo de inicio de los procesos desde el exterior,
Pool
como se creó aquí, superó con creces la soluciónThreadPool
.Es muy fácil de intercambio
Processes
deThreads
. Lea más sobre cómo usar unaThreadPool
solución aquí o aquí .fuente
En algunas versiones de Python estándar reemplazando piscina con la costumbre puede elevar de error:
AssertionError: group argument must be None for now
.Aquí encontré una solución que puede ayudar:
fuente
concurrent.futures.ProcessPoolExecutor
no tiene esta limitación. Puede tener un grupo de procesos anidado sin ningún problema:El código de demostración anterior se probó con Python 3.8.
Crédito: respuesta por jfs
fuente
multiprocessing.Pool
dentro de aProcessPoolExecutor.Pool
también es posible!El problema que encontré fue al intentar importar globales entre módulos, lo que provocó que la línea ProcessPool () se evaluara varias veces.
globals.py
Luego importe de forma segura desde otra parte de su código
fuente
He visto gente que se enfrenta a este problema utilizando
celery
la bifurcación demultiprocessing
llamada billiard (extensiones de grupo de multiprocesamiento), que permite que los procesos demoníacos generen hijos. El recorrido es simplemente reemplazar elmultiprocessing
módulo por:fuente