O módulo multiprocessing em Python oferece um conjunto poderoso de ferramentas para criar programas paralelos que aproveitam ao máximo processadores multi-core. Diferente do multithreading tradicional, que é limitado pelo Global Interpreter Lock (GIL), o multiprocessing permite executar vários processos simultaneamente, cada um com sua própria memória e execução independente.
Princípios básicos do multiprocessing
O multiprocessamento em Python cria processos separados que podem rodar em paralelo em diferentes núcleos da CPU. Cada processo opera em um espaço de memória isolado, eliminando problemas com dados compartilhados comuns no multithreading.
Os principais componentes do módulo multiprocessing incluem:
- Process — classe para criar e gerenciar processos individuais
- Pool — pool de processos para executar várias tarefas de forma eficiente
- Queue — filas para transferência segura de dados entre processos
- Lock — mecanismos de sincronização para controlar acesso a recursos
- Manager — objetos para gerenciar dados compartilhados
Quando usar multiprocessing
O multiprocessing é mais eficaz nos seguintes casos:
Tarefas intensivas em CPU: cálculos matemáticos, processamento de imagens, análise de dados, simulações científicas. Essas tarefas se beneficiam da execução paralela em diferentes núcleos.
Processamento de grandes volumes de dados: quando é necessário aplicar a mesma função a muitos elementos, o multiprocessing pode acelerar significativamente a execução.
Tarefas independentes: operações que não exigem troca frequente de dados entre processos.
Para tarefas intensivas em I/O (arquivos, requisições de rede), é melhor usar programação assíncrona (asyncio) ou multithreading.
Criando e gerenciando processos
Exemplo básico com a classe Process
import multiprocessing
import time
def worker_task(name, duration):
"""Função executada em um processo separado"""
print(f"Processo {name} iniciou")
time.sleep(duration)
print(f"Processo {name} finalizou")
if __name__ == "__main__":
# Criando processos
process1 = multiprocessing.Process(target=worker_task, args=("Worker-1", 3))
process2 = multiprocessing.Process(target=worker_task, args=("Worker-2", 2))
# Iniciando processos
start_time = time.time()
process1.start()
process2.start()
# Aguardando conclusão
process1.join()
process2.join()
end_time = time.time()
print(f"Tempo total de execução: {end_time - start_time:.2f} segundos")
Herdando da classe Process
import multiprocessing
import os
class CustomProcess(multiprocessing.Process):
def __init__(self, name, work_count):
super().__init__()
self.name = name
self.work_count = work_count
def run(self):
"""Método executado no processo"""
print(f"Processo {self.name} (PID: {os.getpid()}) iniciou")
for i in range(self.work_count):
print(f"{self.name}: executando tarefa {i+1}")
time.sleep(1)
print(f"Processo {self.name} finalizou")
if __name__ == "__main__":
processes = []
# Criando vários processos
for i in range(3):
p = CustomProcess(f"Process-{i+1}", 3)
processes.append(p)
p.start()
# Aguardando todos os processos
for p in processes:
p.join()
Trabalhando com pool de processos
O Pool oferece uma interface conveniente para gerenciar