Con il modulo mul­ti­pro­ces­sing in Python è possibile sud­di­vi­de­re il carico di lavoro su più processi per ridurre i tempi di ese­cu­zio­ne com­ples­si­vi. Questa pos­si­bi­li­tà è par­ti­co­lar­men­te utile per i calcoli più complessi o per grandi quantità di dati.

Che cos’è il modulo mul­ti­pro­ces­sing in Python?

Con mul­ti­pro­ces­sing in Python si indica la capacità di eseguire più processi con­tem­po­ra­nea­men­te sfrut­tan­do in modo ottimale la potenza dei sistemi multicore. A dif­fe­ren­za degli approcci single-thread, che elaborano i compiti in sequenza, con il mul­ti­pro­ces­sing è possibile eseguire parti diverse del programma in parallelo e in­di­pen­den­te­men­te le une dalle altre. Ciascun processo dispone di una propria area di memoria e può essere elaborato su core del pro­ces­so­re separati. In questo modo si riducono no­te­vol­men­te i tempi di ese­cu­zio­ne di ope­ra­zio­ni che ri­chie­do­no grande potenza di calcolo o in cui il tempo è un fattore fon­da­men­ta­le.

I campi di ap­pli­ca­zio­ne del mul­ti­pro­ces­sing in Python sono numerosi. Questo modulo trova spesso ap­pli­ca­zio­ne nell’ela­bo­ra­zio­ne dei dati e nell’analisi per elaborare più ve­lo­ce­men­te grandi record di dati e ve­lo­ciz­za­re l’ese­cu­zio­ne di analisi complesse. Può essere uti­liz­za­to anche in ambiti come si­mu­la­zio­ni e calcoli di mo­del­la­zio­ne, ad esempio in ap­pli­ca­zio­ni scien­ti­fi­che, per ridurre i tempi di ese­cu­zio­ne di calcoli complessi. Inoltre, è usato nel campo del web scraping per l’ac­qui­si­zio­ne si­mul­ta­nea di dati da diversi siti web, nell’ela­bo­ra­zio­ne delle immagini o nella visione ar­ti­fi­cia­le (“computer vision”) per aumentare l’ef­fi­cien­za delle ope­ra­zio­ni per l’analisi delle immagini.

Web Hosting
Diventa il n°1 della rete con il provider di hosting n°1 in Europa
  • Di­spo­ni­bi­li­tà garantita al 99,99%
  • Dominio, SSL ed e-mail inclusi
  • As­si­sten­za 24/7 in lingua italiana

In che modo è possibile uti­liz­za­re il mul­ti­pro­ces­sing in Python?

Python offre diverse opzioni per eseguire più processi con­tem­po­ra­nea­men­te. Nelle parti seguenti ti mostriamo tre strumenti uti­liz­za­ti co­mu­ne­men­te: il modulo multiprocessing, la libreria concurrent.futures e il pacchetto joblib.

Il modulo multiprocessing

Il modulo multiprocessing è il modulo standard per eseguire più processi con­tem­po­ra­nea­men­te in Python. Permette la creazione di processi, lo scambio di dati fra tali processi e la sin­cro­niz­za­zio­ne mediante blocchi, liste d’attesa e altri mec­ca­ni­smi.

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()
python

Nell’esempio pre­ce­den­te uti­liz­zia­mo 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 ini­zia­liz­za­ti e si attende la loro con­clu­sio­ne prima di pro­se­gui­re con il programma prin­ci­pa­le. Per l’emissione del risultato uti­liz­zia­mo una f-string, ossia un metodo di for­mat­ta­zio­ne delle stringhe in Python per il col­le­ga­men­to tra le espres­sio­ni. La sequenza è casuale e non de­ter­mi­ni­sti­ca.

È 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]
python

Con 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’in­ter­fac­cia di alto livello per l’ese­cu­zio­ne asincrona e l’ela­bo­ra­zio­ne 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
python

Il 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 con­clu­sio­ne dei compiti ed emette i risultati in una sequenza a piacere.

joblib

La libreria esterna joblib di Python è stata svi­lup­pa­ta per fa­ci­li­ta­re l’ela­bo­ra­zio­ne in parallelo in Python, ad esempio per compiti ri­pe­ti­bi­li come l’ese­cu­zio­ne di funzioni con diversi parametri d’ingresso o per lavorare con grandi quantità di dati. Le funzioni prin­ci­pa­li di joblib sono la pa­ral­le­liz­za­zio­ne dei compiti, la me­mo­riz­za­zio­ne tem­po­ra­nea (caching) dei risultati di funzioni e l’ot­ti­miz­za­zio­ne 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
python

L’espres­sio­ne Parallel(n_jobs=4)(delayed(task)(i) for i in range(1, 11)) ini­zia­liz­za l’ese­cu­zio­ne della funzione task() per i numeri da 1 a 10. Parallel è con­fi­gu­ra­ta con n_job=4 che permette di elaborare fino a quattro job in parallelo. Ri­chia­man­do delayed(task)(i) si crea il compito da eseguire in parallelo per ciascun numero “i” nell’in­ter­val­lo fra 1 e 10. In pratica, la funzione task() viene eseguita con­tem­po­ra­nea­men­te per ciascuno di questi numeri. Il risultato per i numeri da 1 a 10 viene me­mo­riz­za­to in results e quindi emesso.

Vai al menu prin­ci­pa­le