Multithreading en Python
Multithreading se refiere a la técnica de ejecutar múltiples subprocesos simultáneamente dentro de un solo proceso. La ejecución concurrente tiene como objetivo utilizar todo el potencial de los sistemas informáticos y ejecutar tareas incluso más rápido de lo normal.
Los subprocesos son notablemente livianos y tienen una huella de memoria baja en comparación con los procesos. Dado que son muy livianos, crear un nuevo hilo es un proceso rápido. La ejecución de subprocesos requiere menos recursos del sistema, por ejemplo, memoria, para ejecutarse.
Dado que los subprocesos son parte de un proceso, comparten el espacio de memoria con su proceso principal o el proceso que los creó. Multithreading puede parecer demasiado impresionante, pero no todo el brillo es oro. Se debe tener cuidado cuando se trabaja con subprocesos, ya que encontrarse con interbloqueos y condiciones de carrera es bastante común. Desafortunadamente, debido a GIL o Global Interpreter Lock en Python, los subprocesos creados por Python proporcionan intercalación y se ejecutan secuencialmente pero no en paralelo.
Uno puede descubrir el verdadero paralelismo con subprocesos en otros lenguajes de programación como Java. Si uno todavía necesita beneficiarse de múltiples núcleos de CPU usando Python, debería considerar optar por el multiprocesamiento (la técnica de ejecutar varios procesos en paralelo).
Sin embargo, todavía podemos realizar subprocesos múltiples en Python hasta cierto punto. En este artículo, aprenderemos cómo realizar subprocesos múltiples usando Python.
Multithreading en Python
Podemos usar la biblioteca threading
de Python para realizar subprocesos múltiples en Python. Es un módulo incorporado que viene preinstalado con Python oficial y tiene como objetivo proporcionar paralelismo basado en subprocesos en Python. Para obtener más información sobre este módulo y lo que tiene para ofrecer, consulte la documentación oficial aquí.
Ahora, comprendamos cómo usar esta biblioteca para realizar subprocesos múltiples. Consulte el siguiente código de Python para lo mismo.
import threading
class MyThread(threading.Thread):
def __init__(self, low, high):
super(MyThread, self).__init__()
self.low = low
self.high = high
self.total = 0
def run(self):
for x in range(self.low, self.high):
self.total += x
def __str__(self):
return f"Low: {self.low} | High: {self.high}"
thread_one = MyThread(0, 500000)
thread_two = MyThread(5000000, 10000000)
thread_one.start()
thread_two.start()
thread_one.join()
thread_two.join()
result = thread_one.total + thread_two.total
print("Result:", result)
Producción :
Result: 37624997250000
El módulo threading
proporciona una clase Thread
que representa una acción realizada en un hilo separado. Una acción puede ser cualquier cosa, un cálculo matemático, una solicitud POST o GET a un extremo de la API, recuperar algún resultado de un modelo de aprendizaje automático previamente entrenado, una parte de un análisis pesado, etc.
Se debe crear una nueva clase, que herede la clase Thread
, al igual que la clase MyThread
en el código de Python anterior. A continuación, la clase Thread
tiene un método run()
que debe anularse. Esta función contiene la tarea real o el cálculo que realizará el subproceso cuando se active.
Como podemos ver, hemos anulado la función run()
en el código de Python anterior. La función run()
anterior básicamente realiza un bucle en el rango definido por los atributos de clase, low
y height
. Agrega todos los enteros dentro del rango a otro atributo de clase, total
.
Ahora que hemos terminado con una breve descripción de la clase, comprendamos cómo funciona el programa. Consulte los pasos a continuación.
- Se generan o crean dos subprocesos, a saber,
thread_one
ythread_two
. - A continuación, se llama al método
start()
de ambos subprocesos. El métodostart()
ejecuta el métodorun()
por nosotros. - A continuación, se llama al método
join()
para ambos subprocesos. Este método se asegura de que ambos subprocesos esperen el uno al otro antes de terminar. Digamos que el primer hilo completó su tarea5
segundos antes que el segundo hilo. Si dejamos que el programa se ejecute más, nos encontraremos con errores extraños porque el segundo subproceso aún no ha cumplido con su tarea. El métodojoin()
se asegura de que ningún subproceso finalice a menos que todos los demás subprocesos hayan terminado con sus tareas. - Por último, los resultados de ambos subprocesos se suman y el resultado se imprime en la consola.
Tenga en cuenta que es obligatorio hacer que un subproceso convocado espere a que otros subprocesos completen su ejecución; de lo contrario, uno puede encontrarse con resultados erróneos y errores.
Para obtener más información sobre la clase Thread
, consulte la documentación oficial aquí.