Serait-il possible de créer un pool python qui ne soit pas démoniaque? Je veux qu'un pool puisse appeler une fonction qui a un autre pool à l'intérieur.
Je veux cela parce que les processus de démon ne peuvent pas créer de processus. Plus précisément, cela provoquera l'erreur:
AssertionError: daemonic processes are not allowed to have children
Par exemple, considérons le scénario où function_a
a un pool qui s'exécute function_b
qui a un pool qui s'exécute function_c
. Cette chaîne de fonctions échouera, car elle function_b
est exécutée dans un processus démon et les processus démons ne peuvent pas créer de processus.
I want a pool to be able to call a function that has another pool inside
et comment cela interfère avec le fait que les ouvriers sont démonisés.AssertionError: daemonic processes are not allowed to have children
Réponses:
La
multiprocessing.pool.Pool
classe crée les processus de travail dans sa__init__
méthode, les rend démoniaques et les démarre, et il n'est pas possible de redéfinir leurdaemon
attributFalse
avant qu'ils ne soient démarrés (et par la suite, ce n'est plus autorisé). Mais vous pouvez créer votre propre sous-classe demultiprocesing.pool.Pool
(multiprocessing.Pool
c'est juste une fonction wrapper) et substituer votre propremultiprocessing.Process
sous-classe, qui est toujours non démoniaque, à utiliser pour les processus de travail.Voici un exemple complet de la façon de procéder. Les parties importantes sont les deux classes
NoDaemonProcess
etMyPool
en haut et pour appelerpool.close()
etpool.join()
sur votreMyPool
instance à la fin.la source
multiprocessing.freeze_support()
MyPool
au lieu de la valeur par défautPool
? En d'autres termes, en échange de la flexibilité du démarrage des processus enfants, quels coûts dois-je payer? (S'il n'y avait pas de coûts, la normePool
aurait probablement utilisé des processus non démoniaques).Pool
classe a été largement refactorisée, ceProcess
n'est donc plus un simple attribut, mais une méthode, qui renvoie l'instance de processus qu'elle obtient à partir d'un contexte . J'ai essayé d'écraser cette méthode pour renvoyer uneNoDaemonPool
instance, mais cela entraîne une exceptionAssertionError: daemonic processes are not allowed to have children
lorsque le pool est utilisé.J'ai eu la nécessité d'employer un pool non démoniaque dans Python 3.7 et j'ai fini par adapter le code affiché dans la réponse acceptée. Ci-dessous, il y a l'extrait qui crée le pool non démoniaque:
Comme la mise en œuvre actuelle de
multiprocessing
a été largement remaniée pour être basée sur les contextes, nous devons fournir unNoDaemonContext
classe qui a notreNoDaemonProcess
attribut as.MyPool
utilisera alors ce contexte au lieu de celui par défaut.Cela dit, je dois avertir qu'il y a au moins 2 mises en garde à cette approche:
multiprocessing
package et peut donc être interrompu à tout moment.multiprocessing
rendu si difficile l'utilisation de processus non démoniaques, dont beaucoup sont expliqués ici . Le plus convaincant à mon avis est:la source
AttributeError: module 'multiprocessing' has no attribute 'pool'
dans Python 3.8.0import multiprocessing.pool
Le module multitraitement a une interface agréable pour utiliser des pools avec des processus ou des threads. En fonction de votre cas d'utilisation actuel, vous pouvez envisager d'utiliser
multiprocessing.pool.ThreadPool
pour votre pool externe, ce qui entraînera des threads (qui permettent de générer des processus de l'intérieur) par opposition à des processus.Cela pourrait être limité par le GIL, mais dans mon cas particulier (j'ai testé les deux) , le temps de démarrage des processus externes
Pool
tels que créés ici l' emportait de loin sur la solutionThreadPool
.C'est vraiment facile d'échanger
Processes
contreThreads
. En savoir plus sur l'utilisation d'uneThreadPool
solution ici ou ici .la source
Sur certaines versions Python remplaçant la norme piscine à la coutume peut augmenter l' erreur:
AssertionError: group argument must be None for now
.Ici, j'ai trouvé une solution qui peut aider:
la source
concurrent.futures.ProcessPoolExecutor
n'a pas cette limitation. Il peut avoir un pool de processus imbriqué sans aucun problème:Le code de démonstration ci-dessus a été testé avec Python 3.8.
Crédit: réponse de jfs
la source
multiprocessing.Pool
intérieur d'unProcessPoolExecutor.Pool
est également possible!Le problème que j'ai rencontré était en essayant d'importer des globaux entre les modules, provoquant l'évaluation de la ligne ProcessPool () plusieurs fois.
globals.py
Puis importez en toute sécurité depuis ailleurs dans votre code
la source
J'ai vu des gens résoudre ce problème en utilisant
celery
le fork demultiprocessing
appelé billiard (extensions de pool multiprocesseur), qui permet aux processus démoniaques de générer des enfants. La solution consiste simplement à remplacer lemultiprocessing
module par:la source