Quand devons-nous appeler multiprocessing.Pool.join?

94

J'utilise 'multiprocess.Pool.imap_unordered' comme suit

from multiprocessing import Pool
pool = Pool()
for mapped_result in pool.imap_unordered(mapping_func, args_iter):
    do some additional processing on mapped_result

Dois-je appeler pool.closeou pool.joinaprès la boucle for?

hch
la source
J'appelle généralement pool.join()alors pool.close()une fois que je l' ai commencé tous les fils de la piscine, mais je ne l' ai pas essayé d' utiliser pool.imap_unordered()comme itérables.
Bamcclur
8
quel est l'intérêt d'appeler rejoindre ou fermer? Je ne les ai pas appelés et mon code semble fonctionner correctement. Cependant, je crains que ne pas les appeler entraînerait des processus zombies ou d'autres choses subtiles.
hch

Réponses:

111

Non, vous ne le faites pas, mais c'est probablement une bonne idée si vous n'allez plus utiliser la piscine.

Raisons d'appeler pool.closeou pool.joinsont bien dites par Tim Peters dans cet article SO :

Quant à Pool.close (), vous devriez l'appeler quand - et seulement quand - vous n'allez jamais soumettre plus de travail à l'instance de Pool. Ainsi, Pool.close () est généralement appelé lorsque la partie parallélisable de votre programme principal est terminée. Ensuite, les processus de travail prendront fin lorsque tout le travail déjà attribué sera terminé.

C'est également une excellente pratique d'appeler Pool.join () pour attendre la fin des processus de travail. Entre autres raisons, il n'y a souvent pas de bon moyen de signaler les exceptions dans du code parallélisé (les exceptions se produisent dans un contexte vaguement lié à ce que fait votre programme principal), et Pool.join () fournit un point de synchronisation qui peut signaler certaines exceptions qui se sont produites dans des processus de travail que vous ne verriez jamais autrement.

Bamcclur
la source
9
vaut-il mieux appeler l'un avant l'autre?
RSHAP
9
Il semble que les gens aiment appeler les pool.close()premiers et les pool.join()seconds. Cela vous permet d'ajouter du travail entre le pool.close()et pool.join()qui n'a pas besoin d'attendre la fin de l'exécution du pool.
Bamcclur
33
Juste pour ajouter au commentaire de @ Bamcclur - ce n'est pas seulement une bonne idée d'appeler d' pool.close()abord, c'est en fait obligatoire. À partir de la documentation : il faut appeler close()ou terminate()avant d'utiliser join().
Bogd
4
@Bogd Mais pourquoi est-ce obligatoire? Pouvez-vous répondre à cette question, s'il vous plaît?
agdhruv
Une réponse à la question d'agdhruvs serait géniale!
Whip le
44

J'ai eu le même problème de mémoire car l' utilisation de la mémoire continue de croître avec le multiprocessing.pool de Python lorsque je ne l'utilisais pas pool.close()et pool.join()lors de l'utilisation pool.map()avec une fonction qui calculait la distance de Levenshtein. La fonction fonctionnait bien, mais n'était pas correctement collectée sur une machine Win7 64, et l'utilisation de la mémoire continuait de croître de manière incontrôlable à chaque fois que la fonction était appelée jusqu'à ce qu'elle arrête tout le système d'exploitation. Voici le code qui a corrigé la fuite:

stringList = []
for possible_string in stringArray:
    stringList.append((searchString,possible_string))

pool = Pool(5)
results = pool.map(myLevenshteinFunction, stringList)
pool.close()
pool.join()

Après avoir fermé et rejoint le pool, la fuite de mémoire a disparu.

Ulysse Ithaque
la source
1
J'obtenais ERROR: Terminated with signal 15avant d'ajouter le code de nettoyage, pool.close();pool.join();mais après avoir ajouté ce code de nettoyage, je ne reçois pas les messages de la console. donc je soupçonne au moins sur ma version, python 2.7 de C7, que la piscine ne nettoyait peut-être pas exactement.
Trevor Boyd Smith