2010-03-30 7 views
19

Estoy tratando de usar atexit en un Process, pero desafortunadamente no parece funcionar. Aquí hay un código de ejemplo:Python Process no llamará a atexit

import time 
import atexit 
import logging 
import multiprocessing 

logging.basicConfig(level=logging.DEBUG) 

class W(multiprocessing.Process): 
    def run(self): 
     logging.debug("%s Started" % self.name) 

     @atexit.register 
     def log_terminate(): 
      # ever called? 
      logging.debug("%s Terminated!" % self.name) 

     while True: 
      time.sleep(10) 

@atexit.register 
def log_exit(): 
    logging.debug("Main process terminated") 

logging.debug("Main process started") 

a = W() 
b = W() 
a.start() 
b.start() 
time.sleep(1) 
a.terminate() 
b.terminate() 

La salida de este código es:

 
DEBUG:root:Main process started 
DEBUG:root:W-1 Started 
DEBUG:root:W-2 Started 
DEBUG:root:Main process terminated 

que sería de esperar que el W.run.log_terminate() se llamaría cuando a.terminate() y b.terminate() son llamados, y que la salida sea algo likeso (énfasis añadido) !:

 
DEBUG:root:Main process started 
DEBUG:root:W-1 Started 
DEBUG:root:W-2 Started 
DEBUG:root:W-1 Terminated! 
DEBUG:root:W-2 Terminated! 
DEBUG:root:Main process terminated 

¿Por qué no es este trabajo, y es que hay una mejor manera de registrar un mensaje (del Process context) cuando termina un Process?

Gracias por su aporte, es muy apreciado.

Solución

EDIT: basado en la solución sugerida por Alex Martelli, los siguientes funciona como se espera:

import sys 
import time 
import atexit 
import signal 
import logging 
import multiprocessing 

logging.basicConfig(level=logging.DEBUG) 

class W(multiprocessing.Process): 
    def run(self): 
     logging.debug("%s Started" % self.name) 

     def log_terminate(num, frame): 
      logging.debug("%s Terminated" % self.name) 
      sys.exit() 
     signal.signal(signal.SIGTERM, log_terminate) 
     while True: 
      time.sleep(10) 

@atexit.register 
def log_exit(): 
    logging.debug("Main process terminated") 

logging.debug("Main process started") 
a = W() 
b = W() 
a.start() 
b.start() 
time.sleep(1) 
a.terminate() 
b.terminate() 

Vale la pena tener en cuenta el siguiente comentario en la documentación atexit:

Nota: las funciones registradas a través de este módulo no se invocan cuando una señal mata el programa, cuando se detecta un error interno fatal de Python o cuando se llama a os._exit().

Respuesta

17

Como the docs decir,

En Unix esto se hace mediante el SIGTERM señal; en Windows TerminateProcess() se utiliza. Tenga en cuenta que los manejadores de salida y las cláusulas finally de , etc., no se ejecutarán en .

Si está en Unix, usted debería ser capaz de intercepción SIGTERM con signal, y llevar a cabo lo que sea "actividades de terminación" que necesitan; sin embargo, no sé de una solución multiplataforma.