La forma más pythonica de matar un hilo después de un período de tiempo.

Me gustaría ejecutar un proceso en un subproceso (que está iterando sobre una tabla de base de datos grande). Mientras el hilo se está ejecutando, solo quiero que el progtwig espere. Si ese hilo tarda más de 30 segundos, quiero matarlo y hacer otra cosa. Al matar el hilo, quiero decir que quiero que cese la actividad y libere los recursos con gracia.

Pensé que la mejor manera de hacerlo era a través de las funciones de join(delay) e is_alive() y un Event . Al usar la join(delay) puedo hacer que mi progtwig espere 30 segundos a que finalice el hilo, y al usar la función is_alive() puedo determinar si el hilo ha terminado su trabajo. Si no ha terminado su trabajo, se establece el evento y el hilo sabe que debe dejar de trabajar en ese punto.

¿Es este enfoque válido y es esta la forma más pythonica de abordar mi statement de problemas?

Aquí hay un código de ejemplo:

 import threading import time # The worker loops for about 1 minute adding numbers to a set # unless the event is set, at which point it breaks the loop and terminates def worker(e): data = set() for i in range(60): data.add(i) if not e.isSet(): print "foo" time.sleep(1) else: print "bar" break e = threading.Event() t = threading.Thread(target=worker, args=(e,)) t.start() # wait 30 seconds for the thread to finish its work t.join(30) if t.is_alive(): print "thread is not done, setting event to kill thread." e.set() else: print "thread has already finished." 

El uso de un evento en este caso funciona bien como mecanismo de señalización, y en realidad se recomienda en los documentos del módulo de subprocesos .

Si desea que sus hilos se detengan correctamente, conviértalos en no demoníacos y utilice un mecanismo de señalización adecuado, como un Event .

Al verificar la terminación del hilo, los tiempos de espera casi siempre introducen espacio para el error. Por lo tanto, mientras se usa el .join() con un tiempo de espera para que la decisión inicial de desencadenar el evento esté bien, la verificación final debe realizarse con un .join() sin un tiempo de espera.

 # wait 30 seconds for the thread to finish its work t.join(30) if t.is_alive(): print "thread is not done, setting event to kill thread." e.set() # The thread can still be running at this point. For example, if the # thread's call to isSet() returns right before this call to set(), then # the thread will still perform the full 1 second sleep and the rest of # the loop before finally stopping. else: print "thread has already finished." # Thread can still be alive at this point. Do another join without a timeout # to verify thread shutdown. t.join() 

Esto se puede simplificar a algo como esto:

 # Wait for at most 30 seconds for the thread to complete. t.join(30) # Always signal the event. Whether the thread has already finished or not, # the result will be the same. e.set() # Now join without a timeout knowing that the thread is either already # finished or will finish "soon." t.join() 

Llego tarde a este juego, pero he estado luchando con una pregunta similar y lo siguiente parece resolver el problema a la perfección para mí Y me permite realizar una comprobación y limpieza del estado del subproceso básico cuando el subproceso del daemonized se cierra:

 import threading import time import atexit def do_work(): i = 0 @atexit.register def goodbye(): print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" % (i, threading.currentThread().ident)) while True: print i i += 1 time.sleep(1) t = threading.Thread(target=do_work) t.daemon = True t.start() def after_timeout(): print "KILL MAIN THREAD: %s" % threading.currentThread().ident raise SystemExit threading.Timer(2, after_timeout).start() 

Rendimientos:

 0 1 KILL MAIN THREAD: 140013208254208 'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]