2015-12-29 18 views
5

Ho alcuni sottoprocessi (usando multiprocessing) e quando si fermano, ognuno di loro ha bisogno di fare un ultimo lavoro. Qualcosa come il seguente, che non ha funzionato però ...Come registrare la funzione "atexit" nel sottoprocesso di multiprocessing di 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() 

Quindi, come ho potuto fare questo?

+0

Controlla http://stackoverflow.com/questions/1231599/python-multiprocessing-exit-elegantly-how che è simile a quello che stai cercando di realizzare. –

risposta

1

I processi avviati tramite multiprocessing non escono normalmente e le funzioni atexit non vengono mai richiamate. Si deve eseguire roba pulizia manualmente tramite un try/finally del blocco, per esempio:

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

O, se si vuole veramente utilizzare atexit (vedi sotto per gli svantaggi):

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

Perché non sottoporre a elaborazione l'uscita normalmente?

Tecnicamente, poiché they quit via os._exit(), salta qualsiasi lavoro di pulizia (incluse le funzioni atexit, __del__() e finalizzatori weakref).

Il motivo alla base di questa decisione è che le operazioni di pulizia rischiano di essere eseguite nel momento sbagliato, nel processo sbagliato. La maggior parte del codice che utilizza atexit (o altri meccanismi) si aspetta che il codice venga eseguito solo una volta e solo quando l'interprete principale si chiude (ad esempio, si può usare atexit per rimuovere una directory temporanea). Eseguendo le funzioni atexit ogni volta che si chiude un sottoprocesso, si rompe questa aspettativa e possono accadere cose brutte.

Quindi, anche se è possibile eseguire atexit funzioni tramite atexit._run_exitfuncs(), evitare di farlo, sia perché la funzione è non documentata e perché si può non essere l'unico utente del atexit (altre librerie di terze parti possono utilizzare, e si può introdurre bug nel loro codice).

+0

Questa è stata una decisione assurda. le funzioni atexit non si aspettano di essere chiamate da "main". Si aspettano di essere chiamati nel processo in cui sono stati registrati. quindi atexit ha semplicemente bisogno di memorizzare il pid di registrazione per sapere se possono essere chiamati. Tutti i moduli che usano atexit ora sono resi inutilizzabili all'interno di un processo di multiprocessing ... costringendomi a usare Popen invece e sottaceto il loro stato. In realtà ho biforcato il multiprocessing solo per rimettere a posto le corrette pulizie. –