Entonces, ¿cómo sale este código de la instrucción while cuando se inicia el hilo? (No considere la sangría)

class ThreadUrl(threading.Thread):
    """Threaded Url Grab"""
    def __init__(self, queue, out_queue):
        threading.Thread.__init__(self)
        self.queue = queue
        self.out_queue = out_queue

    def run(self):
        while True:
            #grabs host from queue
            host = self.queue.get()

            #grabs urls of hosts and then grabs chunk of webpage
            url = urllib2.urlopen(host)
            chunk = url.read()

            #place chunk into out queue
            self.out_queue.put(chunk)

            #signals to queue job is done
            self.queue.task_done()

** EDITAR *

El código que inicia el hilo:

def main():

#spawn a pool of threads, and pass them queue instance
    for i in range(5):
        t = ThreadUrl(queue)
        t.setDaemon(True)
        t.start()

    queue.join()
2
Shaokan 18 ago. 2011 a las 13:40

4 respuestas

La mejor respuesta

No tiene que salir de la instrucción while para que el código finalice. Todo lo que está sucediendo aquí es que el hilo ha consumido todo en la cola, en cuyo punto queue.join() regresa.

Tan pronto como se devuelva la llamada a queue.join() en el código principal, el código principal se cerrará y debido a que marcó el hilo como un demonio, la aplicación completa se cerrará y su hilo de fondo será eliminado.

5
Duncan 18 ago. 2011 a las 10:49

La respuesta rápida: no, a menos que se genere una excepción en cualquier lugar, que depende de las funciones / métodos llamados en run.

Por supuesto, existe la posibilidad de que su hilo sea suspendido / detenido de otro hilo, lo que efectivamente termina su ciclo while.

1
Constantinius 18 ago. 2011 a las 09:46

Puede pasar block = False o timeout = 5 a su método self.queue.get (). Esto generará una excepción Queue.Empty si no quedan elementos en la cola. De lo contrario, AFAIK, self.queue.get () bloqueará todo el bucle para que no se alcancen aún más intentos de interrupción adicionales.

def run(self):
    while True:
        #grabs host from queue
        try:
            host = self.queue.get(block=False)
        except Queue.Empty, ex:
            break
        #grabs urls of hosts and then grabs chunk of webpage
        url = urllib2.urlopen(host)
        chunk = url.read()

        #place chunk into out queue
        self.out_queue.put(chunk)

        #signals to queue job is done
        self.queue.task_done()

Otro enfoque sería colocar una bandera de "Detener" en la cola después de que se hayan agregado todos los demás elementos. Luego, en el hilo, marque esta bandera de detención y rompa si se encuentra.

Eg.

host = self.queue.get()
if host == 'STOP':
    #Still need to signal that the task is done, else your queue join() will wait forever
    self.queue.task_done()
    break
0
Werner Smit 18 ago. 2011 a las 14:29

Su código solo se romperá si se produce una excepción durante la ejecución del contenido del bucle while True ... no es la mejor manera de salir de un hilo, pero podría funcionar.

Si desea salir correctamente de su hilo, intente reemplazar el while True con algo como while self.continue_loop:

class ThreadUrl(threading.Thread):
    """Threaded Url Grab"""
    def __init__(self, queue, out_queue):
        threading.Thread.__init__(self)
        self.queue = queue
        self.out_queue = out_queue
        self.continue_loop = True

    def run(self):
        while self.continue_loop:
            #grabs host from queue
            host = self.queue.get()

            #grabs urls of hosts and then grabs chunk of webpage
            url = urllib2.urlopen(host)
            chunk = url.read()

            #place chunk into out queue
            self.out_queue.put(chunk)

            #signals to queue job is done
            self.queue.task_done()

Y para iniciar / detener los hilos:

def main():

#spawn a pool of threads, and pass them queue instance
    threads = []
    for i in range(5):
        t = ThreadUrl(queue, out_queue)
        t.setDaemon(True)
        t.start()
        threads.append(t)

    for t in threads:
       t.continue_loop = False
       t.join()

    queue.join()
1
Cédric Julien 18 ago. 2011 a las 09:56