La biblioteca de subprocesos se puede usar para ejecutar cualquier Python invocable en su propio subproceso. Para hacer esto, cree una instancia de Thread y proporcione el invocable que desea ejecutar como objetivo, como se muestra en el código que se proporciona a continuación:
Código #1:
# Code to execute in an independent thread import time def countdown(n): while n > 0: print('T-minus', n) n -= 1 time.sleep(5) # Create and launch a thread from threading import Thread t = Thread(target = countdown, args =(10, )) t.start()
Cuando se crea una instancia de subproceso, no comienza a ejecutarse hasta que se invoca su start()
método (que invoca la función de destino con los argumentos que proporcionó). Los subprocesos se ejecutan en su propio subproceso a nivel del sistema (p. ej., un subproceso POSIX o subprocesos de Windows) que está completamente administrado por el sistema operativo host. Una vez iniciados, los subprocesos se ejecutan de forma independiente hasta que vuelve la función de destino.
Código n.º 2: consultar una instancia de subproceso para ver si aún se está ejecutando.
if t.is_alive(): print('Still running') else: print('Completed')
También se puede solicitar unirse a un hilo, que espera a que termine.
t.join()
El intérprete sigue ejecutándose hasta que finalizan todos los subprocesos. Para subprocesos de ejecución prolongada o tareas en segundo plano que se ejecutan para siempre, considere hacer que el subproceso sea demoníaco.
Código #3:
t = Thread(target = countdown, args =(10, ), daemon = True) t.start()
Los subprocesos demoníacos no se pueden unir. Sin embargo, se destruyen automáticamente cuando finaliza el subproceso principal. Más allá de las dos operaciones que se muestran, no hay muchas otras cosas que hacer con los hilos. Por ejemplo, no hay operaciones para terminar un subproceso, señalar un subproceso, ajustar su programación o realizar cualquier otra operación de alto nivel. Para tener estas características, constrúyalas por su cuenta. Para poder terminar subprocesos, el subproceso debe estar programado para sondear la
salida en los puntos seleccionados. Por ejemplo, coloque su hilo en una clase como la que se menciona en el siguiente código:
Código #4: Poner el hilo en una clase.
class CountdownTask: def __init__(self): self._running = True def terminate(self): self._running = False def run(self, n): while self._running and n > 0: print('T-minus', n) n -= 1 time.sleep(5) c = CountdownTask() t = Thread(target = c.run, args =(10, )) t.start() ... # Signal termination c.terminate() # Wait for actual termination (if needed) t.join()
El sondeo de terminación de subprocesos puede ser complicado de coordinar si los subprocesos realizan operaciones de bloqueo, como E/S. Por ejemplo, es posible que un subproceso bloqueado indefinidamente en una operación de E/S nunca regrese para verificar si se eliminó. Para manejar correctamente este caso, el subproceso debe programarse cuidadosamente para utilizar bucles de tiempo de espera como se muestra en el código que se proporciona a continuación.
Código #5:
class IOTask: def terminate(self): self._running = False def run(self, sock): # sock is a socket # Set timeout period sock.settimeout(5) while self._running: # Perform a blocking I/O operation w/timeout try: data = sock.recv(8192) break except socket.timeout: continue # Continued processing ... # Terminated return
Debido a un bloqueo de intérprete global (GIL), los subprocesos de Python están restringidos a un modelo de ejecución que solo permite que un subproceso se ejecute en el intérprete en un momento dado. Por esta razón, los subprocesos de Python generalmente no deben usarse para tareas computacionalmente intensivas en las que se intenta lograr el paralelismo en varias CPU. Son mucho más adecuados para el manejo de E/S y la ejecución concurrente en código que realiza operaciones de bloqueo (por ejemplo, espera de E/S, espera de resultados de una base de datos, etc.).
Código #6: Subprocesos definidos a través de la herencia de la clase Subproceso
from threading import Thread class CountdownThread(Thread): def __init__(self, n): super().__init__() self.n = 0 def run(self): while self.n > 0: print('T-minus', self.n) self.n -= 1 time.sleep(5) c = CountdownThread(5) c.start()
Aunque esto funciona, introduce una dependencia adicional entre el código y la biblioteca de subprocesos. Es decir, solo el código resultante se puede usar en el contexto de los subprocesos, mientras que la técnica que se mostró anteriormente implica escribir código sin una dependencia explícita de los subprocesos. Al liberar su código de tales dependencias, se vuelve utilizable en otros contextos que pueden o no involucrar subprocesos. Por ejemplo, uno podría ejecutar el código en un proceso separado usando el módulo de multiprocesamiento usando el código que se proporciona a continuación:
Código #7:
import multiprocessing c = CountdownTask(5) p = multiprocessing.Process(target = c.run) p.start() ...
Nuevamente, esto solo funciona si CountdownTask class
se ha escrito de una manera que sea neutral para los medios reales de concurrencia (subprocesos, procesos, etc.).
Publicación traducida automáticamente
Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA