Sobes.tech
Junior

O que é paralelismo na programação?

sobes.tech IA

Resposta da IA

O paralelismo na programação é a execução de várias tarefas simultaneamente ou a aparência de execução simultânea, o que permite melhorar o desempenho e a capacidade de resposta das aplicações.

Distinguem-se várias formas de paralelismo:

  • Multiprocessamento: Utiliza vários processos independentes, cada um com o seu próprio espaço de endereçamento. Isto evita a limitação do GIL (Global Interpreter Lock) no CPython e é adequado para tarefas que utilizam intensamente a CPU.

    import multiprocessing
    import time
    
    def worker(num):
        """Algum trabalho"""
        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 os workers terminaram")
    
  • Multithreading: Utiliza vários threads dentro de um mesmo processo, partilhando o mesmo espaço de endereçamento. Devido ao GIL no CPython, os threads não são executados em paralelo em diferentes núcleos para tarefas CPU-bound, mas são eficientes para tarefas I/O-bound.

    import threading
    import time
    
    def worker(num):
        """Algum trabalho"""
        time.sleep(1) # Simulação de operação I/O
        print(f'Thread {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 os threads terminaram")
    
  • Programação assíncrona (Asyncio): Utiliza um único thread e um ciclo de eventos (event loop) para gerir a execução de tarefas. Adequado para aplicações I/O-bound de alta carga e servidores web. Não bloqueia a execução enquanto espera por I/O.

    import asyncio
    import time
    
    async def worker(num):
        """Algum trabalho assíncrono"""
        await asyncio.sleep(1) # Espera assíncrona de I/O
        print(f'Worker assí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 os workers assíncronos terminaram")
    
    if __name__ == '__main__':
        asyncio.run(main())
    

A escolha da abordagem depende da natureza da tarefa:

Abordagem Tarefas CPU-bound Tarefas I/O-bound GIL Uso de memória
Multiprocessamento Excelente Bom Contorna Grande (seu próprio processo)
Multithreading Mau (por causa do GIL) Excelente Bloqueia Pequeno (processo comum)
Assíncrono Mau Excelente Não bloqueia Pequeno (um único thread)

O paralelismo requer uma gestão cuidadosa de sincronização e recursos para evitar condições de corrida e deadlocks.