Tiempo fuera decorador en una función de multiprocesamiento

Tengo este decorador tomado directamente de un ejemplo que encontré en la red:

class TimedOutExc(Exception): pass def timeout(timeout): def decorate(f): def handler(signum, frame): raise TimedOutExc() def new_f(*args, **kwargs): old = signal.signal(signal.SIGALRM, handler) signal.alarm(timeout) try: result = f(*args, **kwargs) except TimedOutExc: return None finally: signal.signal(signal.SIGALRM, old) signal.alarm(0) return result new_f.func_name = f.func_name return new_f return decorate 

Lanza una excepción si la función f se agota.

Bueno, funciona, pero cuando uso este decorador en una función de multiprocesamiento y se detiene debido a un tiempo de espera, no finaliza los procesos involucrados en el cálculo. ¿Cómo puedo hacer eso?

No quiero lanzar una excepción y detener el progtwig. Básicamente, lo que quiero es cuando se agote el tiempo, haga que devuelva Ninguno y luego finalice los procesos involucrados.

Si bien estoy de acuerdo con el punto principal de la respuesta de Aaron, me gustaría elaborar un poco.

Los procesos iniciados por multiprocessing deben detenerse en la función a decorar ; No creo que esto se pueda hacer en general y simplemente desde el decorador en sí (la función decorada es la única entidad que sabe qué cálculos lanzó).

En lugar de tener la función decorada que captura SIGALARM , también puede capturar su excepción personalizada TimedOutExc ; esto podría ser más flexible. Tu ejemplo se convertiría entonces en:

 class TimedOutExc(Exception): """ Raised when a timeout happens """ def timeout(timeout): """ Return a decorator that raises a TimedOutExc exception after timeout seconds, if the decorated function did not return. """ def decorate(f): def handler(signum, frame): raise TimedOutExc() def new_f(*args, **kwargs): old_handler = signal.signal(signal.SIGALRM, handler) signal.alarm(timeout) result = f(*args, **kwargs) # f() always returns, in this scheme signal.signal(signal.SIGALRM, old_handler) # Old signal handler is restred signal.alarm(0) # Alarm removed return result new_f.func_name = f.func_name return new_f return decorate @timeout(10) def function_that_takes_a_long_time(): try: # ... long, parallel calculation ... except TimedOutExc: # ... Code that shuts down the processes ... # ... return None # Or exception raised, which means that the calculation is not complete 

Dudo que se pueda hacer con un decorador: un decorador es una envoltura para una función; La función es una caja negra. No hay comunicación entre el decorador y la función que envuelve.

Lo que debe hacer es volver a escribir el código de su función para usar el controlador SIGALRM para terminar cualquier proceso que haya iniciado.