2017-08-14 2 views
2

J'utilisais this answer pour exécuter des commandes parallèles avec multiprocessing en Python sur une machine Linux.multiprocessing renvoie "trop ​​de fichiers ouverts" mais en utilisant "with ... as" le corrige. Pourquoi?

Mon code a fait quelque chose comme:

import multiprocessing 
import logging 

def cycle(offset): 
    # Do stuff 

def run(): 
    for nprocess in process_per_cycle: 
     logger.info("Start cycle with %d processes", nprocess) 
     offsets = list(range(nprocess)) 
     pool = multiprocessing.Pool(nprocess) 
     pool.map(cycle, offsets) 

Mais je recevais cette erreur: OSError: [Errno 24] Too many open files
Ainsi, le code a été d'ouvrir trop de descripteur de fichier, à savoir: il commençait trop de processus et ne pas les mettre fin à .

Je l'ai fixé en remplaçant les deux dernières lignes avec ces lignes:

with multiprocessing.Pool(nprocess) as pool: 
     pool.map(cycle, offsets) 

Mais je ne sais pas exactement pourquoi ces lignes fixes elle.

Que se passe-t-il en dessous de with?

+0

Voici le [code source] (https://github.com/python/cpython/blob/master/Lib/multiprocessing/pool.py#L607-L611) chaque processus appelle 'self.terminate()' – salparadise

+0

La version 'with' appelle implicitement' pool.close() 'après que' pool.map() 'soit revenu. Selon les docs, cela "Empêche d'autres tâches d'être soumises au pool.Une fois toutes les tâches terminées, les processus de travail vont sortir". Cela provoque probablement la fermeture des fichiers ouverts à chaque tâche. – martineau

+0

Ai-je tort, ou @COLDSPEED a répondu à la question et maintenant il est effacé? Je n'ai pas été capable de le lire en profondeur, mais j'aimerais ... Mais maintenant c'est parti ... Quelqu'un sait pourquoi la question a été rejetée? – nephewtom

Répondre

2

Vous créez de nouveaux processus dans une boucle, puis oubliez de les fermer une fois que vous avez terminé. En conséquence, il arrive un moment où vous avez trop de processus ouverts. C'est une mauvaise idée.

Vous pouvez résoudre ce problème en utilisant un gestionnaire de contexte qui appelle automatiquement pool.terminate ou en appelant manuellement le pool.terminate. Sinon, pourquoi ne pas créer un pool en dehors de la boucle juste une fois, puis envoyer des tâches aux processus à l'intérieur?

pool = multiprocessing.Pool(nprocess) # initialise your pool 
for nprocess in process_per_cycle: 
    ...  
    pool.map(cycle, offsets) # delegate work inside your loop 

pool.close() # shut down the pool 

Pour plus d'informations, vous pouvez prendre connaissance de la documentation multiprocessing.Pool.

+0

Appeler manuellement 'pool.terminate' sera probablement la chose à faire ici. Je n'ai pas pu créer la piscine à l'extérieur, car je voulais la changer à chaque itération. Ainsi, dans chacun d'entre eux, le nombre de processus engendrés augmentait. Par exemple, si process_per_cycle était [2, 4, 8], chaque itération engendrerait 2, 4 et 8 processus. – nephewtom

+0

@nephewtom Oui, ce serait l'autre option, si vous ne pouvez pas utiliser le gestionnaire de contexte. –

+0

Bien que la question de savoir pourquoi 'avec' le résout, reste sans réponse ... – nephewtom

0

C'est le gestionnaire de contexte. L'utilisation avec garantit que vous ouvrez et fermez les fichiers correctement. Pour le comprendre en détail, je recommanderais cet article https://jeffknupp.com/blog/2016/03/07/python-with-context-managers/

+0

Il est évident que c'est un gestionnaire de contexte. Mais pourquoi son utilisation ici fait-elle que cela fonctionne? –