# Python Multiprocessing: Processamento paralelo de processos

Ao utilizar o Python `multiprocessing`, você poderá **dividir cargas de trabalho entre vários processos**, reduzindo o tempo total de execução. Ele é especialmente vantajoso para a realização de cálculos intensivos e para lidar com grandes volumes de dados.

## O que é Python multiprocessing?

O `multiprocessing` em Python possibilita a execução de vários processos simultaneamente, para se obter o máximo desempenho de sistemas **multinúcleo**. Ao contrário de abordagens de um único *thread*, nas quais tarefas são executadas sequencialmente, o multiprocessamento do Python permite que diferentes partes de um programa funcionem paralelamente e de forma independente. Cada processo ganha sua própria área de memória e pode ser executado em núcleos separados, o que reduz significativamente o tempo de execução de operações computacionalmente intensivas ou de críticas em termos de tempo.

As aplicações do Python `multiprocessing` são variadas. Em manipulações e análises de dados, o `multiprocessing` é geralmente utilizado para processar grandes conjuntos de dados mais rapidamente e acelerar análises complexas. Em simulações e cálculos de modelagem, como em aplicações científicas, o `multiprocessing` pode ser empregado para diminuir o tempo de execução de cálculos complexos. Ele também pode ser usado no *web scraping* para coletar dados de várias páginas web simultaneamente, e na visão computacional e no processamentos de imagem, para melhorar a eficiência das operações de análise.

## Possibilidades do Python multiprocessing

A linguagem de programação Python permite que o `multiprocessing` seja implementado de várias formas. Abaixo, apresentamos as três mais comuns: o módulo `multiprocessing`, a biblioteca `concurrent.futures` e o pacote `joblib`.

### Módulo `multiprocessing`

O módulo `multiprocessing` é o **módulo padrão do Python `multiprocessing`**. Ele permite a criação de processos, a troca de dados entre processos e a sincronização por meio de travas, filas e outros mecanismos. Observe:

```python
import multiprocessing
def task(n):
    result = n * n
    print(f"Result: {result}")
if __name__ == "__main__":
    processes = []
    for i in range(1, 6):
        process = multiprocessing.Process(target=task, args=(i,))
        processes.append(process)
        process.start()
    for process in processes:
        process.join()
```

No exemplo acima, estamos usando a classe `multiprocessing.Process` para criar e iniciar processos que executam a função `task()` — essa função calcula o quadrado do número definido como argumento. Os processos são inicializados e aguardamos a conclusão deles antes que o programa principal continue. O resultado é exibido na forma de **f-string**, método de [formatação de strings em Python](https://www.ionos.com/digitalguide/websites/web-development/python-string-format/ "Formatação de strings em Python") que combina expressões. A ordem de execução dos processos é aleatória e não determinística.

Também é possível criar um pool de processos com o Python `multiprocessing`:

```python
import multiprocessing
def task(n):
    return n * n
if __name__ == "__main__":
    with multiprocessing.Pool() as pool:
        results = pool.map(task, range(1, 6))
        print(results)  # Output: [1, 4, 9, 16, 25]
```

Com `pool.map()`, a função `task()` é aplicada a uma sequência de dados, e os resultados são coletados e exibidos.

### Biblioteca `concurrent.futures`

Esse módulo fornece uma interface de alto nível para execuções assíncronas e processamentos paralelos de processos. Ele utiliza o ***Pool Executor** *para executar tarefas em um* pool *de processos ou* threads*. O módulo `concurrent.futures` oferece uma maneira mais simples de lidar com tarefas assíncronas e, em muitos casos, é mais fácil de usar do que o módulo Python `multiprocessing`.

```python
import concurrent.futures
def task(n):
    return n * n
with concurrent.futures.ProcessPoolExecutor() as executor:
    futures = [executor.submit(task, i) for i in range(1, 6)]
    for future in concurrent.futures.as_completed(futures):
        print(future.result()) # result in random order
```

O código utiliza o módulo `concurrent.futures` para processar tarefas em paralelo, por meio do `ProcessPoolExecutor`. Nele, a função `task(n)` é chamada para números de 1 a 5. O método `as_completed()` espera a conclusão das tarefas e imprime os **resultados em qualquer ordem**.

### `joblib`

`joblib` é uma biblioteca externa do Python. Ela foi desenvolvida para simplificar o processamento paralelo, especialmente útil em tarefas repetitivas, como na execução de funções com diferentes parâmetros de entrada ou em trabalhos com grandes volumes de dados. As principais funções da biblioteca `joblib` incluem a paralelização de tarefas, o **armazenamento em cache dos resultados das funções** e a otimização dos recursos de memória e computação.

```python
from joblib import Parallel, delayed
def task(n):
    return n * n
results = Parallel(n_jobs=4)(delayed(task)(i) for i in range(1, 11))
print(results) # Output: Results of the function for numbers from 1 to 10
```

A expressão `Parallel(n_jobs=4)(delayed(task)(i) for i in range(1, 11))` inicia a execução paralela da função `task()` para os números de 1 a 10. O `Parallel` é configurado com `n_jobs=4`, permitindo que até quatro *jobs* sejam processados simultaneamente. O chamado `delayed(task)(i)` cria a tarefa a ser executada em paralelo para cada número `i` no intervalo de 1 a 10 — isso significa que a função `task()` será chamada simultaneamente para cada um desses números. Os resultados para os números de 1 a 10 são armazenados em `results` e depois exibidos.


This is a markdown version of: [https://www.ionos.com/pt-br/digitalguide/sites-de-internet/desenvolvimento-web/python-multiprocessing/](https://www.ionos.com/pt-br/digitalguide/sites-de-internet/desenvolvimento-web/python-multiprocessing/) for AI/LLM consumption.