2012-05-03 11 views
7

Tengo un programa de Python que genera varios hilos. Estos hilos duran entre 2 segundos y 30 segundos. En el hilo principal quiero rastrear cada vez que termina cada hilo e imprimir un mensaje. Si solo secuencialmente .join() todos los hilos y el primer hilo dura 30 segundos y otros se completan mucho antes, no podría imprimir un mensaje antes: todos los mensajes se imprimirán después de 30 segundos.En el enhebrado de Python, ¿cómo puedo rastrear la finalización de un hilo?

Básicamente quiero bloquear hasta que haya terminado cualquier hilo. Tan pronto como se completa un hilo, imprime un mensaje al respecto y vuelve al bloqueo si todavía hay otros hilos vivos. Si todos los hilos están terminados, salga del programa.

Una forma en que podría pensar es tener una cola que se pasa a todos los hilos y bloquear en queue.get(). Siempre que se reciba un mensaje de la cola, imprímalo, verifique si hay otros hilos vivos usando threading.active_count() y, de ser así, vuelva al bloqueo en queue.get(). Esto funcionaría, pero aquí todos los hilos deben seguir la disciplina de enviar un mensaje a la cola antes de terminar.

Me pregunto si esta es la manera convencional de lograr este comportamiento o hay alguna otra/mejor manera?

Respuesta

3

Aquí hay una variación en la respuesta de @ detly que le permite especificar los mensajes desde el hilo principal, en lugar de imprimirlos de sus funciones objetivo. Esto crea una función de envoltura que llama a su destino y luego imprime un mensaje antes de terminar. Puede modificar esto para realizar cualquier tipo de limpieza estándar después de que se complete cada subproceso.

#!/usr/bin/python 

import threading 
import time 

def target1(): 
    time.sleep(0.1) 
    print "target1 running" 
    time.sleep(4) 

def target2(): 
    time.sleep(0.1) 
    print "target2 running" 
    time.sleep(2) 

def launch_thread_with_message(target, message, args=[], kwargs={}): 
    def target_with_msg(*args, **kwargs): 
     target(*args, **kwargs) 
     print message 
    thread = threading.Thread(target=target_with_msg, args=args, kwargs=kwargs) 
    thread.start() 
    return thread 

if __name__ == '__main__': 
    thread1 = launch_thread_with_message(target1, "finished target1") 
    thread2 = launch_thread_with_message(target2, "finished target2") 

    print "main: launched all threads" 

    thread1.join() 
    thread2.join() 

    print "main: finished all threads" 
0

No estoy seguro de que veo el problema con el uso: threading.activeCount()

para rastrear el número de hilos que aún están activos?

Incluso si no sabe cuántos subprocesos va a iniciar antes de comenzar, parece bastante fácil de seguir. Por lo general, genero colecciones de hilos a través de la comprensión de listas, luego una simple comparación con activeCount para el tamaño de la lista puede indicar cuántos terminaron.

Ver aquí: http://docs.python.org/library/threading.html

Alternativamente, una vez que tenga el hilo objetos sólo se puede utilizar el método .isAlive dentro de los objetos de hilo para comprobar.

acabo de comprobar por tirar esto en un programa multi-hilo que tengo y se ve bien:

for thread in threadlist: 
     print(thread.isAlive()) 

me da una lista de Verdadero/Falso como los hilos de conectar y desconectar. Así que deberías poder hacer eso y verificar si hay algo falso para ver si algún hilo ha terminado.

1

Puede dejar que los subprocesos inserten sus resultados en threading.Queue. Espere otro hilo en esta cola e imprima el mensaje tan pronto como aparezca un nuevo elemento.

4

El hilo debe verificarse mediante la llamada Thread.is_alive().

2

Lo que sugeriría es loop como esto

while len(threadSet) > 0: 
    time.sleep(1) 
    for thread in theadSet: 
     if not thread.isAlive() 
      print "Thread "+thread.getName()+" terminated" 
      threadSet.remove(thread) 

Hay un segundo sueño 1, por lo que habrá un ligero retraso entre la terminación de hilo y el mensaje que se está imprimiendo. Si puedes vivir con este retraso, entonces creo que esta es una solución más simple que la que propusiste en tu pregunta.

3

¿Por qué no hacer que los propios hilos impriman un mensaje de finalización o llamar a alguna otra devolución de llamada de compleción cuando haya terminado?

Puede simplemente join estos subprocesos de su programa principal, por lo que verá un montón de mensajes de finalización y su programa terminará cuando todo haya terminado, según sea necesario.

He aquí una demostración rápida y sencilla:

#!/usr/bin/python 

import threading 
import time 

def really_simple_callback(message): 
    """ 
    This is a really simple callback. `sys.stdout` already has a lock built-in, 
    so this is fine to do. 
    """  
    print message 

def threaded_target(sleeptime, callback): 
    """ 
    Target for the threads: sleep and call back with completion message. 
    """ 
    time.sleep(sleeptime) 
    callback("%s completed!" % threading.current_thread()) 

if __name__ == '__main__': 
    # Keep track of the threads we create 
    threads = [] 

    # callback_when_done is effectively a function 
    callback_when_done = really_simple_callback 

    for idx in xrange(0, 10): 
     threads.append(
      threading.Thread(
       target=threaded_target, 
       name="Thread #%d" % idx, 
       args=(10 - idx, callback_when_done) 
      ) 
     ) 

    [t.start() for t in threads] 
    [t.join() for t in threads] 

    # Note that thread #0 runs for the longest, but we'll see its message first! 
0

Utilizo una técnica ligeramente diferente debido a la naturaleza de los hilos que utilicé en mi aplicación. Para ilustrar esto, este es un fragmento de un programa de prueba de la correa le escribí a una clase andamio barrera para mi clase de roscado:

while threads: 
     finished = set(threads) - set(threading.enumerate()) 
     while finished: 
      ttt = finished.pop() 
      threads.remove(ttt) 
     time.sleep(0.5) 

¿Por qué lo hago de esta manera? En mi código de producción, tengo un límite de tiempo, por lo que la primera línea realmente lee "while threads and time.time() < cutoff_time". Si llego al punto de corte, entonces tengo un código para indicarle a los hilos que se apaguen.

Cuestiones relacionadas