2015-12-29 2 views
5

J'ai quelques sous-processus (en utilisant le multitraitement) et quand ils s'arrêtent, chacun d'eux a besoin de faire un travail final. Quelque chose comme ce qui suit, qui n'a pas fonctionné si ...Comment enregistrer la fonction "atexit" dans le sous-processus multiprocesseur de python?

import multiprocessing 
import atexit 

def final(): 
    print "final work" 

def worker(): 
    print 'Doing some work' 
    atexit.register(final) 

if __name__ == '__main__': 
    p = multiprocessing.Process(target=worker) 
    p.start() 
    p.join() 

Alors, comment pourrais-je faire cela?

+0

Vérifiez http://stackoverflow.com/questions/1231599/python-multiprocessing-exit-elegantly-qui est similaire à ce que vous essayez d'accomplir. –

Répondre

1

Les processus démarrés via le multitraitement ne sortent pas normalement et les fonctions atexit ne sont jamais appelées. Vous devez exécuter des trucs de nettoyage manuellement via un bloc try/finally, par exemple:

def worker(): 
    try: 
     print('Doing some work') 
    finally: 
     final() 

Ou, si vous voulez vraiment utiliser atexit (voir ci-dessous pour les inconvénients):

def worker(): 
    try: 
     print('Doing some work') 
    finally: 
     atexit._run_exitfuncs() 

Pourquoi les sous-processus ne sortent-ils pas normalement?

Techniquement, car they quit via os._exit(), en ignorant tout travail de nettoyage (y compris les fonctions atexit, __del__() et les finaliseurs weakref).

La raison de cette décision est que les opérations de nettoyage risquent d'être exécutées au mauvais moment, dans le mauvais processus. La majeure partie du code qui utilise atexit (ou d'autres mécanismes) s'attend à ce que le code ne soit exécuté qu'une seule fois et seulement quand l'interpréteur principal se termine (par exemple, on peut utiliser atexit pour supprimer un répertoire temporaire). En exécutant atexit fonctions chaque fois qu'un sous-processus se ferme, vous brisez cette attente et de mauvaises choses peuvent se produire.

Donc, même si vous pouvez exécuter atexit fonctions via atexit._run_exitfuncs(), évitez de le faire, à la fois parce que la fonction est non documentée et parce que vous ne pouvez pas être le seul utilisateur de atexit (autres bibliothèques de tiers peut l'utiliser, et vous pouvez introduire bugs dans leur code).

+0

C'était une décision absurde. Les fonctions atexit ne s'attendent pas à être appelées depuis "main". Ils s'attendent à être appelés dans le processus dans lequel ils ont été enregistrés. donc atexit a simplement besoin de stocker le pid d'enregistrement pour savoir s'ils peuvent être appelés. Tous les modules qui utilisent atexit sont maintenant rendus inutilisables dans un travail multiprocesseur ... me forçant à utiliser Popen à la place et à décaper leur propre état. J'ai réellement bifurqué multiprocessing juste pour remettre les nettoyages appropriés. –