Saltar al contenido

¿Cómo detener un hilo en bucle en Python?

Solución:

Función de tapón roscado

En lugar de subclasificar threading.Thread, se puede modificar la función para permitir la parada con una bandera.

Necesitamos un objeto, accesible a la función en ejecución, al que le ponemos la bandera para que deje de ejecutarse.

Nosotros podemos usar threading.currentThread() objeto.

import threading
import time


def doit(arg):
    t = threading.currentThread()
    while getattr(t, "do_run", True):
        print ("working on %s" % arg)
        time.sleep(1)
    print("Stopping as you wish.")


def main():
    t = threading.Thread(target=doit, args=("task",))
    t.start()
    time.sleep(5)
    t.do_run = False
    t.join()

if __name__ == "__main__":
    main()

El truco es que el hilo en ejecución puede tener propiedades adicionales adjuntas. La solución se basa en supuestos:

  • el hilo tiene una propiedad “do_run” con valor predeterminado True
  • El proceso principal de conducción puede asignar al hilo iniciado la propiedad “do_run” a False.

Al ejecutar el código, obtenemos el siguiente resultado:

$ python stopthread.py                                                        
working on task
working on task
working on task
working on task
working on task
Stopping as you wish.

Píldora para matar – usando Evento

Otra alternativa es usar threading.Event como argumento de función. Es por defecto False, pero el proceso externo puede “configurarlo” (para True) y la función puede aprender sobre él usando wait(timeout) función.

Podemos wait con tiempo de espera cero, pero también podemos usarlo como temporizador para dormir (usado a continuación).

def doit(stop_event, arg):
    while not stop_event.wait(1):
        print ("working on %s" % arg)
    print("Stopping as you wish.")


def main():
    pill2kill = threading.Event()
    t = threading.Thread(target=doit, args=(pill2kill, "task"))
    t.start()
    time.sleep(5)
    pill2kill.set()
    t.join()

Editar: probé esto en Python 3.6. stop_event.wait() bloquea el evento (y por lo tanto el bucle while) hasta su liberación. No devuelve un valor booleano. Utilizando stop_event.is_set() funciona en su lugar.

Detener varios hilos con una pastilla

La ventaja de la píldora para matar se ve mejor si tenemos que detener varios hilos a la vez, ya que una sola píldora funcionará para todos.

los doit no cambiará en absoluto, solo el main maneja los hilos de manera un poco diferente.

def main():
    pill2kill = threading.Event()
    tasks = ["task ONE", "task TWO", "task THREE"]

    def thread_gen(pill2kill, tasks):
        for task in tasks:
            t = threading.Thread(target=doit, args=(pill2kill, task))
            yield t

    threads = list(thread_gen(pill2kill, tasks))
    for thread in threads:
        thread.start()
    time.sleep(5)
    pill2kill.set()
    for thread in threads:
        thread.join()

Esto se ha preguntado antes en Stack. Vea los siguientes enlaces:

  • ¿Hay alguna forma de matar un hilo en Python?
  • Detener un hilo después de un cierto período de tiempo

Básicamente, solo necesita configurar el hilo con una función de parada que establece un valor centinela que el hilo comprobará. En su caso, tendrá algo en su bucle que verifique el valor centinela para ver si ha cambiado y, si lo ha hecho, el bucle puede romperse y el hilo puede morir.

Leí las otras preguntas en Stack, pero todavía estaba un poco confundido al comunicarme entre clases. Así es como lo abordé:

Utilizo una lista para guardar todos mis hilos en el __init__ método de mi clase wxFrame: self.threads = []

Como se recomienda en ¿Cómo detener un hilo en bucle en Python? Utilizo una señal en mi clase de hilo que está configurada en True al inicializar la clase de subprocesamiento.

class PingAssets(threading.Thread):
    def __init__(self, threadNum, asset, window):
        threading.Thread.__init__(self)
        self.threadNum = threadNum
        self.window = window
        self.asset = asset
        self.signal = True

    def run(self):
        while self.signal:
             do_stuff()
             sleep()

y puedo detener estos hilos iterando sobre mis hilos:

def OnStop(self, e):
        for t in self.threads:
            t.signal = False
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *