Il modulo multiprocessing in Python: l’elaborazione dei processi in parallelo
Con il modulo multiprocessing in Python è possibile suddividere il carico di lavoro su più processi per ridurre i tempi di esecuzione complessivi. Questa possibilità è particolarmente utile per i calcoli più complessi o per grandi quantità di dati.
Che cos’è il modulo multiprocessing in Python?
Con multiprocessing in Python si indica la capacità di eseguire più processi contemporaneamente sfruttando in modo ottimale la potenza dei sistemi multicore. A differenza degli approcci single-thread, che elaborano i compiti in sequenza, con il multiprocessing è possibile eseguire parti diverse del programma in parallelo e indipendentemente le une dalle altre. Ciascun processo dispone di una propria area di memoria e può essere elaborato su core del processore separati. In questo modo si riducono notevolmente i tempi di esecuzione di operazioni che richiedono grande potenza di calcolo o in cui il tempo è un fattore fondamentale.
I campi di applicazione del multiprocessing in Python sono numerosi. Questo modulo trova spesso applicazione nell’elaborazione dei dati e nell’analisi per elaborare più velocemente grandi record di dati e velocizzare l’esecuzione di analisi complesse. Può essere utilizzato anche in ambiti come simulazioni e calcoli di modellazione, ad esempio in applicazioni scientifiche, per ridurre i tempi di esecuzione di calcoli complessi. Inoltre, è usato nel campo del web scraping per l’acquisizione simultanea di dati da diversi siti web, nell’elaborazione delle immagini o nella visione artificiale (“computer vision”) per aumentare l’efficienza delle operazioni per l’analisi delle immagini.
- Certificato SSL e protezione DDoS
- Velocità, flessibilità e scalabilità
- Dominio e consulente personale
- 1 anno gratis del gestionale di fatturazione elettronica FlexTax
In che modo è possibile utilizzare il multiprocessing in Python?
Python offre diverse opzioni per eseguire più processi contemporaneamente. Nelle parti seguenti ti mostriamo tre strumenti utilizzati comunemente: il modulo multiprocessing
, la libreria concurrent.futures
e il pacchetto joblib
.
Il modulo multiprocessing
Il modulo multiprocessing
è il modulo standard per eseguire più processi contemporaneamente in Python. Permette la creazione di processi, lo scambio di dati fra tali processi e la sincronizzazione mediante blocchi, liste d’attesa e altri meccanismi.
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()
pythonNell’esempio precedente utilizziamo la classe multiprocessing.Process
per creare e avviare i processi che eseguono la funzione task()
. Questa funzione calcola il quadrato del numero indicato. I processi vengono inizializzati e si attende la loro conclusione prima di proseguire con il programma principale. Per l’emissione del risultato utilizziamo una f-string, ossia un metodo di formattazione delle stringhe in Python per il collegamento tra le espressioni. La sequenza è casuale e non deterministica.
È anche possibile creare un pool di processi con multiprocessing
in 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]
pythonCon pool.map()
si applica la funzione task()
a una sequenza di dati e i risultati vengono quindi raccolti ed emessi.
La libreria concurrent.futures
Questo modulo offre un’interfaccia di alto livello per l’esecuzione asincrona e l’elaborazione di processi in parallelo. Il modulo utilizza l’esecutore di un pool per eseguire i compiti su un pool di processi o thread. concurrent.futures
è una soluzione semplice per elaborare compiti asincroni e in molti casi è più facile da gestire rispetto al modulo multiprocessing
in 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
pythonIl codice utilizza il modulo concurrent.futures
per elaborare i compiti in parallelo con ProcessPoolExecutor
. A tal fine viene assegnata la funzione task(n)
per numeri da 1 a 5. Il metodo as_completed()
attende la conclusione dei compiti ed emette i risultati in una sequenza a piacere.
joblib
La libreria esterna joblib
di Python è stata sviluppata per facilitare l’elaborazione in parallelo in Python, ad esempio per compiti ripetibili come l’esecuzione di funzioni con diversi parametri d’ingresso o per lavorare con grandi quantità di dati. Le funzioni principali di joblib
sono la parallelizzazione dei compiti, la memorizzazione temporanea (caching) dei risultati di funzioni e l’ottimizzazione delle risorse di memoria e di calcolo.
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
pythonL’espressione Parallel(n_jobs=4)(delayed(task)(i) for i in range(1, 11))
inizializza l’esecuzione della funzione task()
per i numeri da 1 a 10. Parallel
è configurata con n_job=4
che permette di elaborare fino a quattro job in parallelo. Richiamando delayed(task)(i)
si crea il compito da eseguire in parallelo per ciascun numero “i” nell’intervallo fra 1 e 10. In pratica, la funzione task()
viene eseguita contemporaneamente per ciascuno di questi numeri. Il risultato per i numeri da 1 a 10 viene memorizzato in results
e quindi emesso.