Sobes.tech
Junior

¿Qué es la paralelización en programación?

sobes.tech AI

Respuesta de la IA

El paralelismo en programación es la ejecución de varias tareas simultáneamente o la apariencia de ejecución simultánea, lo que permite mejorar el rendimiento y la capacidad de respuesta de las aplicaciones.

Se distinguen varias formas de paralelismo:

  • Multiprocesamiento: Utiliza varios procesos independientes, cada uno con su propio espacio de direcciones. Esto evita la limitación del GIL (Global Interpreter Lock) en CPython y es adecuado para tareas que utilizan intensamente la CPU.

    import multiprocessing
    import time
    
    def worker(num):
        """Algún trabajo"""
        time.sleep(1)
        print(f'Worker {num} terminado')
    
    if __name__ == '__main__':
        processes = []
        for i in range(5):
            p = multiprocessing.Process(target=worker, args=(i,))
            processes.append(p)
            p.start()
    
        for p in processes:
            p.join()
        print("Todos los workers han terminado")
    
  • Multithreading: Utiliza varios hilos dentro de un mismo proceso, compartiendo el mismo espacio de direcciones. Debido al GIL en CPython, los hilos no se ejecutan en paralelo en diferentes núcleos para tareas CPU-bound, pero son eficientes para tareas I/O-bound.

    import threading
    import time
    
    def worker(num):
        """Algún trabajo"""
        time.sleep(1) # Simulación de operación I/O
        print(f'Hilo {num} terminado')
    
    threads = []
    for i in range(5):
        t = threading.Thread(target=worker, args=(i,))
        threads.append(t)
        t.start()
    
    for t in threads:
        t.join()
    print("Todos los hilos han terminado")
    
  • Programación asíncrona (Asyncio): Utiliza un solo hilo y un ciclo de eventos (event loop) para gestionar la ejecución de tareas. Es adecuada para aplicaciones I/O-bound de alta carga y servidores web. No bloquea la ejecución mientras espera I/O.

    import asyncio
    import time
    
    async def worker(num):
        """Algún trabajo asíncrono"""
        await asyncio.sleep(1) # Espera asíncrona de I/O
        print(f'Worker asíncrono {num} terminado')
    
    async def main():
        tasks = []
        for i in range(5):
            task = asyncio.create_task(worker(i))
            tasks.append(task)
        await asyncio.gather(*tasks)
        print("Todos los workers asíncronos han terminado")
    
    if __name__ == '__main__':
        asyncio.run(main())
    

La elección del enfoque depende de la naturaleza de la tarea:

Enfoque Tareas CPU-bound Tareas I/O-bound GIL Uso de memoria
Multiprocesamiento Excelente Bueno Lo evita Grande (su propio proceso)
Multithreading Malo (por GIL) Excelente Bloquea Pequeño (proceso compartido)
Asíncrono Malo Excelente No bloquea Pequeño (un hilo)

El paralelismo requiere una gestión cuidadosa de la sincronización y los recursos para evitar condiciones de carrera y bloqueos mutuos.