En savoir plus sur le multitraitement Python (à partir d'un article de PMOTW ) et j'aimerais avoir des éclaircissements sur ce que fait exactement la join()
méthode.
Dans un ancien tutoriel de 2008, il indique que sans l' p.join()
appel dans le code ci-dessous, "le processus enfant restera inactif et ne se terminera pas, devenant un zombie que vous devez tuer manuellement".
from multiprocessing import Process
def say_hello(name='world'):
print "Hello, %s" % name
p = Process(target=say_hello)
p.start()
p.join()
J'ai ajouté une impression du PID
ainsi qu'un time.sleep
pour tester et pour autant que je sache, le processus se termine tout seul:
from multiprocessing import Process
import sys
import time
def say_hello(name='world'):
print "Hello, %s" % name
print 'Starting:', p.name, p.pid
sys.stdout.flush()
print 'Exiting :', p.name, p.pid
sys.stdout.flush()
time.sleep(20)
p = Process(target=say_hello)
p.start()
# no p.join()
dans les 20 secondes:
936 ttys000 0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000 0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001 0:00.13 -bash
après 20 secondes:
947 ttys001 0:00.13 -bash
Le comportement est le même avec l' p.join()
ajout à la fin du fichier. Le module Python de la semaine offre une explication très lisible du module ; "Pour attendre qu'un processus ait terminé son travail et se soit arrêté, utilisez la méthode join ().", Mais il semble qu'au moins OS X le fasse de toute façon.
Je me demande aussi le nom de la méthode. La .join()
méthode concatène-elle quelque chose ici? S'agit-il de concaténer un processus avec sa fin? Ou partage-t-il simplement un nom avec la .join()
méthode native de Python ?
la source
CPU, Memory resources
sont séparés du processus parent, puis sontjoin
à nouveau modifiés une fois le processus enfant terminé?Réponses:
La
join()
méthode, lorsqu'elle est utilisée avecthreading
oumultiprocessing
, n'est pas liée àstr.join()
- elle ne concatène en fait rien. Au contraire, cela signifie simplement "attendez que ce [thread / processus] se termine". Le nomjoin
est utilisé car l'multiprocessing
API du module est censée ressembler à l'threading
API duthreading
module et que le module utilisejoin
pour sonThread
objet. Utiliser le termejoin
pour signifier «attendre qu'un thread se termine» est courant dans de nombreux langages de programmation, donc Python vient de l'adopter également.Maintenant, la raison pour laquelle vous voyez le délai de 20 secondes avec et sans l'appel à
join()
est que par défaut, lorsque le processus principal est prêt à quitter, il appellera implicitementjoin()
toutes lesmultiprocessing.Process
instances en cours d'exécution . Ce n'est pas aussi clairement indiqué dans lamultiprocessing
documentation qu'il devrait l'être, mais il est mentionné dans la section Directives de programmation :Vous pouvez remplacer ce comportement en définissant l'
daemon
indicateur sur leProcess
àTrue
avant de démarrer le processus:Si vous faites cela, le processus enfant sera terminé dès que le processus principal sera terminé :
la source
p.daemon=True
c'était pour "démarrer un processus d'arrière-plan qui s'exécute sans bloquer la sortie du programme principal". Mais si "Le processus démon se termine automatiquement avant que le programme principal ne se termine", à quoi sert-il exactement?daemonic
processus enfant n'est pas très sûr, car le processus va se terminer sans permettre de nettoyer les ressources ouvertes qu'il peut avoir .. (suite).multiprocessing
API est conçue pour imiter l'threading
API le plus fidèlement possible. Lesthreading.Thread
objets démoniaques sont arrêtés dès que le thread principal se termine, donc lesmultiprocesing.Process
objets démoniaques se comportent de la même manière.Sans le
join()
, le processus principal peut se terminer avant le processus enfant. Je ne sais pas dans quelles circonstances cela conduit au zombieisme.L'objectif principal de
join()
est de s'assurer qu'un processus enfant est terminé avant que le processus principal ne fasse quoi que ce soit qui dépend du travail du processus enfant.L'étymologie de
join()
est que c'est l'opposé defork
, qui est le terme courant dans les systèmes d'exploitation de la famille Unix pour créer des processus enfants. Un seul processus "fourche" en plusieurs, puis "rejoint" en un seul.la source
join()
carjoin()
c'est ce qui est utilisé pour attendre la fin d'unthreading.Thread
objet, et l'multiprocessing
API est censée imiter l'threading
API autant que possible.join()
est nécessaire dans le cas où le thread principal a besoin des résultats du travail des sous-threads. Par exemple, si vous effectuez le rendu de quelque chose et attribuez 1/4 de l'image finale à chacun des 4 sous-processus, et que vous souhaitez afficher l'image entière une fois l'opération terminée.Je ne vais pas expliquer en détail ce que
join
fait, mais voici l'étymologie et l'intuition derrière cela, ce qui devrait vous aider à vous souvenir plus facilement de sa signification.L'idée est que l'exécution " fourche " en plusieurs processus dont l'un est le maître, les autres ouvriers (ou "esclaves"). Lorsque les nœuds de calcul ont terminé, ils «rejoignent» le maître afin que l'exécution en série puisse reprendre.
La
join
méthode oblige le processus maître à attendre qu'un travailleur le rejoigne. La méthode aurait mieux été appelée "wait", puisque c'est le comportement réel qu'elle provoque dans le maître (et c'est ce qu'elle appelle dans POSIX, bien que les threads POSIX l'appellent aussi "join"). La jonction se produit uniquement comme un effet des fils qui coopèrent correctement, ce n'est pas quelque chose que le maître fait .Les noms «fork» et «join» sont utilisés dans ce sens dans le multiprocessing depuis 1963 .
la source
join
peut-être précédé son utilisation en référence à la concaténation, par opposition à l'inverse.join()
est utilisé pour attendre la fermeture des processus de travail. Il faut appelerclose()
outerminate()
avant d'utiliserjoin()
.Comme @Russell l'a mentionné, la jointure est comme l'opposé de fork (qui génère des sous-processus).
Pour que la jointure s'exécute, vous devez exécuter,
close()
ce qui empêchera toute autre tâche d'être soumise au pool et quittera une fois toutes les tâches terminées. Sinon, l'exécution seterminate()
terminera simplement en arrêtant immédiatement tous les processus de travail."the child process will sit idle and not terminate, becoming a zombie you must manually kill"
cela est possible lorsque le processus principal (parent) se termine mais que le processus enfant est toujours en cours d'exécution et qu'une fois terminé, il n'a pas de processus parent auquel retourner son état de sortie.la source
L'
join()
appel garantit que les lignes suivantes de votre code ne sont pas appelées avant que tous les processus de multitraitement ne soient terminés.Par exemple, sans le
join()
, le code suivant sera appelérestart_program()
avant même la fin des processus, ce qui est similaire à asynchrone et n'est pas ce que nous voulons (vous pouvez essayer):la source
Pour attendre qu'un processus ait terminé son travail et quitte, utilisez la méthode join ().
et
Remarque Il est important de joindre () le processus après l'avoir terminé afin de donner à la machine d'arrière-plan le temps de mettre à jour le statut de l'objet pour refléter l'arrêt.
Ceci est un bon exemple m'a aidé à le comprendre: ici
Une chose que j'ai remarquée personnellement, c'est que mon processus principal a été mis en pause jusqu'à ce que l'enfant ait terminé son processus en utilisant la méthode join () qui a vaincu le point de moi d'utiliser
multiprocessing.Process()
en premier lieu.la source