Programação Paralela e Concorrente em Python

0 – Python
4 – Paralela e Concorrente
4.1 – Multithreading (threading)
4.2 – Multiprocessamento (multiprocessing)
4.3 – Assíncrona (asyncio)
4.4 – async ou await
4.4 – Distribuida
LEGENDA
Nivel_1
Nivel_2
Nivel_3

Paralelismo executa múltiplas tarefas ao mesmo tempo fisicamente. Concorrência lida com várias tarefas avançando em sobreposição. Primeiramente, o paralelismo exige múltiplos núcleos de CPU. Por exemplo, processar 10 imagens simultaneamente em 10 núcleos. Já a concorrência pode rodar em um único núcleo. Ela alterna entre tarefas para dar a sensação de simultaneidade. A voz passiva é usada aqui: “as tarefas são intercaladas pelo escalonador”. Quando utilizar cada uma? Paralelismo para tarefas com CPU intensiva. Concorrência para operações de I/O (rede, disco, banco de dados). Python oferece threading, asyncio e multiprocessing para isso. Vamos explorar cada abordagem com exemplos práticos. Três subtítulos guiarão você pelas principais técnicas. Ao final, você saberá qual ferramenta escolher.

Threading: concorrência para i/o-bound

Threading permite múltiplas threads dentro de um único processo. No Python, o GIL (Global Interpreter Lock) limita a execução paralela. Portanto, threads não aceleram código com CPU intensivo. Por outro lado, threads são excelentes para operações de I/O. Por exemplo, baixar vários arquivos da internet simultaneamente. Quando usar threading? Em aplicações com muitas esperas externas. A voz passiva é aplicada: “os bloqueios de I/O são liberados durante a espera”. Exemplo de threading para downloads simultâneos:

O threading reduz drasticamente o tempo total para I/O. Neste exemplo, a versão sequencial leva cerca de 5 segundos. A versão com threads leva apenas o tempo da operação mais longa (~2s). Isso é o poder da concorrência para operações de espera.

Multiprocessing: paralelismo para cpu-bound

Multiprocessing cria processos separados, cada um com seu próprio GIL. Isso permite usar múltiplos núcleos da CPU simultaneamente. Quando usar multiprocessing? Em tarefas que consomem muito processamento. Por exemplo, cálculos matemáticos, processamento de imagens ou criptografia. A sobrecarga de criar processos é maior que a de threads. Portanto, use apenas para tarefas realmente pesadas. Exemplo de multiprocessing para calcular números primos:

O ganho com multiprocessing é próximo ao número de núcleos. Em uma máquina com 4 núcleos, a aceleração pode chegar a 3.5x. Isso é paralelismo real, não apenas concorrência.

Asyncio: concorrência assíncrona eficiente

Asyncio usa um event loop para gerenciar tarefas concorrentes. Ele não usa threads nem processos, apenas uma única thread. Quando usar asyncio? Em aplicações com muitas conexões de rede. Por exemplo, servidores web, chats ou proxies. A vantagem é o baixo consumo de memória e overhead reduzido. A desvantagem é que todo o código precisa ser assíncrono. Exemplo de asyncio para múltiplas requisições HTTP:

Asyncio é ideal para milhares de conexões simultâneas. Ele escala melhor que threads para I/O intensivo. A fórmula de eficiência é: \(E = \frac{R_{\text{asyncio}}}{R_{\text{threading}}} \approx 1.5\) Para muitos casos, asyncio usa menos memória e CPU. A escolha final depende do seu problema específico. Threading é mais simples para iniciantes em concorrência. Multiprocessing é obrigatório para CPU-bound. Asyncio é o futuro para servidores de alta performance. Domine as três técnicas e resolva qualquer desafio.

Deixe um comentário