Processos Paralelos em Python: Paralelismo Verdadeiro

Processos paralelos executam código simultaneamente em múltiplos núcleos.
Isso é chamado de true parallelism ou paralelismo verdadeiro.
Primeiramente, cada processo tem seu próprio interpretador e memória.
Por exemplo, 8 processos podem rodar em 8 núcleos de CPU ao mesmo tempo.
Além disso, processos não compartilham o GIL (Global Interpreter Lock).
A voz passiva é usada aqui: “o sistema operacional gerencia a distribuição entre núcleos”.
Quando utilizar processos paralelos? Em tarefas com CPU intensiva.
Por exemplo, processamento de imagens, simulações científicas ou machine learning.
Também em qualquer tarefa que exija todo o poder da máquina.
Python oferece o módulo multiprocessing e o concurrent.futures.
Vamos explorar características, ganhos e limitações.
Três subtítulos guiarão você pelo verdadeiro paralelismo.
Ao final, você dominará a execução paralela em Python.

Multiprocessing vs. threading: a diferença crucial

Threads são leves, mas limitadas pelo GIL em CPU-bound.
Processos são mais pesados, mas executam em paralelo verdadeiro.
Quando escolher processos? Quando o gargalo é CPU, não I/O.
A criação de um processo é mais cara que uma thread.
No entanto, o ganho em paralelismo compensa para tarefas longas.
A voz passiva é aplicada: “a memória é duplicada para cada processo”.
Exemplo comparativo entre threads e processos para CPU-bound:

Processos mostram aceleração próxima ao número de núcleos.
Threads mostram aceleração próxima de 1.0 devido ao GIL.
Essa é a diferença fundamental entre concorrência e paralelismo.

Comunicação e sincronização entre processos

Processos paralelos precisam se comunicar para trocar resultados.
Diferente de threads, eles não compartilham memória automaticamente.
Portanto, usamos filas (Queue), pipes ou memória compartilhada.
A serialização (pickle) é necessária para enviar dados entre processos.
Isso adiciona overhead, mas é inevitável para isolamento.
Quando usar memória compartilhada? Para grandes arrays numéricos.
A voz passiva é usada aqui: “os dados são copiados por valor entre processos”.
Exemplo de comunicação com Queue entre processos paralelos:

Queues são seguras e ideais para padrões produtor-consumidor.
Arrays compartilhados são eficientes para dados numéricos.
Sempre use locks ao modificar memória compartilhada.

Escalabilidade e lei de amdahl

O ganho com processos paralelos não é linear infinito.
A lei de Amdahl descreve o limite teórico de aceleração.
A fórmula é: \(S = \frac{1}{(1 – P) + \frac{P}{N}}\)
Onde P é a fração paralelizável e N é o número de núcleos.
Por exemplo, com 90% paralelizável e 8 núcleos, o ganho máximo é 4.7x.
Portanto, nem todo código pode ser perfeitamente paralelizado.
A voz passiva é aplicada: “partes sequenciais são executadas em apenas um núcleo”.
Exemplo demonstrando a lei de Amdahl na prática:

Observe que quanto maior a fração sequencial, menor o ganho.
Portanto, identifique e otimize os gargalos sequenciais primeiro.
Processos paralelos são ferramentas poderosas, mas não mágicas.
Use-os com sabedoria e meça sempre o ganho real.
Para muitos problemas, o paralelismo verdadeiro transforma horas em minutos.
Experimente e veja seu código voar em múltiplos núcleos.

Deixe um comentário