Multihilo y multiprocesamiento en Python

PythonBeginner
Practicar Ahora

Introducción

Adentrate en un mundo donde la revolución industrial ha transformado la sociedad, y el ajetreo de los patrones de vida del siglo XIX victoriano modela las calles de adoquín. Aquí, entre las callejuelas nebulosas llenas del ruido de los carruajes tirados por caballos y el zumbido lejano de la maquinaria de las fábricas, vive un personaje cuyo talento cautiva a las multitudes concurridas: un artista ambulante conocido por su increíble habilidad para multitarea.

Nuestro artista, llamado Oliver, es famoso por hacer malabarismos con objetos mientras se mantiene en equilibrio sobre una monocicleta, toca el armónico y resuelve acertijos complejos al mismo tiempo. Para la sorpresa de su audiencia, las actuaciones de Oliver son fluidas y eficientes, un testimonio de su dominio de las actividades concurrentes. Este Laboratorio tiene como objetivo imitar la destreza de Oliver para la multitarea explorando las capacidades de subprocesamiento y multiprocesamiento de Python, asegurando que los programadores puedan manejar múltiples tareas simultáneamente sin problemas.

Comprendiendo los subprocesos

En este paso, aprenderás los conceptos básicos de subprocesamiento en Python. El subprocesamiento te permite ejecutar múltiples operaciones de manera concurrente, lo que hace que parezca que tu programa está haciendo más de una cosa a la vez, al igual que la habilidad de Oliver para hacer malabarismos mientras está en bicicleta.

Abre un archivo llamado simple_threads.py en el directorio ~/project con el siguiente contenido:

import threading
import time

def print_numbers():
    for i in range(1, 6):
        time.sleep(1)
        print(i)

## Crea dos subprocesos
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_numbers)

## Inicia ambos subprocesos
thread1.start()
thread2.start()

## Espera a que ambos subprocesos terminen
thread1.join()
thread2.join()

print("Hecho con los números!")

Ejecuta el código anterior en la terminal con:

python simple_threads.py

Deberías ver que los números se imprimen intercalados de ambos subprocesos, seguidos de "Hecho con los números!":

1
1
2
2
3
3
4
4
5
5
Hecho con los números!

Aprovechando el Multiprocesamiento

Ahora, usemos el multiprocesamiento para acelerar los cálculos. El multiprocesamiento en Python permite la ejecución de múltiples procesos, los cuales pueden ejecutarse en diferentes núcleos de CPU, lo que reduce el tiempo total requerido para tareas limitadas por la CPU.

Abre un archivo llamado process_prime.py en el directorio ~/project con el siguiente contenido:

from multiprocessing import Process
import math

def is_prime(num):
    """
    Verifica si un número es primo.
    """
    if num <= 1:
        return False
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            return False
    return True

def compute_primes(start, end):
    """
    Calcula los números primos dentro de un rango dado.
    """
    prime_numbers = [num for num in range(start, end) if is_prime(num)]
    print(f"Primos en el rango {start}-{end}: {prime_numbers}")

processes = []
## Creando dos procesos
for i in range(0, 20000, 10000):
    ## Crea un nuevo proceso con la función compute_primes como objetivo y pasa el rango como argumentos
    p = Process(target=compute_primes, args=(i, i+10000))
    processes.append(p)
    ## Inicia el proceso
    p.start()

## Espera a que todos los procesos terminen
for p in processes:
    p.join()

print("Hecho con el cálculo de números primos!")

Ejecuta el script en la terminal:

python process_prime.py

Esto imprimirá los números primos encontrados en los rangos especificados y mostrará un mensaje de finalización:

Primos en el rango 0-10000: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241,
......
9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973]
Primos en el rango 10000-20000: [10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193,
......
19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997]
Hecho con el cálculo de números primos!

Resumen

En este laboratorio, emprendimos un viaje interesante para desentrañar las sutilezas del subprocesamiento y el multiprocesamiento en Python, similar a las actuaciones de múltiples capas de los artistas callejeros victorianos. Comenzamos haciendo malabarismos con tareas utilizando subprocesos y luego escalamos a procesar operaciones pesadas a través de los núcleos de CPU. Este ejercicio no solo demostró las capacidades de paralelismo de Python, sino también reveló cómo estas técnicas tienen significado en el mundo real, similar a las exhibiciones multifacéticas de habilidad de nuestro personaje, Oliver.

Lo que debes llevar de este laboratorio es una comprensión clara de los subprocesos de Python para tareas limitadas por E/S y de los procesos para tareas limitadas por CPU, lo que mejora efectivamente tu rendimiento de codificación y hace que tus aplicaciones sean más eficientes.