CodeGym /Corsi /Python SELF IT /Aggirare il GIL

Aggirare il GIL

Python SELF IT
Livello 26 , Lezione 4
Disponibile

11.1 Global Interpreter Lock

Global Interpreter Lock (GIL) è un meccanismo nell'interprete CPython che garantisce che solo un thread esegua byte-code Python alla volta. Il GIL impedisce l'esecuzione parallela dei thread, il che può influire negativamente sulle prestazioni dei programmi multithreading, specialmente sui processori multi-core.

Motivi per cui esiste il GIL

Semplificazione della gestione della memoria: il GIL semplifica la gestione della memoria e il garbage collection, rendendo Python più semplice da implementare.

Sicurezza dei thread: il GIL previene le condizioni di race, rendendo l'esecuzione del codice sicura per i thread senza la necessità di utilizzare i lock.

Problemi causati dal GIL

Prestazioni limitate: i programmi multithreading che eseguono compiti intensivi dal punto di vista computazionale non possono sfruttare appieno i vantaggi dei processori multi-core a causa delle limitazioni del GIL.

Distorsione delle prestazioni: i programmi che utilizzano intensamente i thread per eseguire compiti possono incontrare un peggioramento delle prestazioni a causa del contesto switch tra i thread.

Attualmente ci sono 4 modi principali per "aggirare il GIL":

11.2 Utilizzo del multiprocessing (multiprocessing)

Il modulo multiprocessing permette di creare processi che vengono eseguiti in parallelo e non sono limitati dal GIL, poiché ogni processo ha il proprio interprete Python e memoria.

Esempio:


import multiprocessing

def worker(num):
    print(f'Worker: {num}')
            
def main():
    processes = []
    for i in range(5):
        p = multiprocessing.Process(target=worker, args=(i,))
        processes.append(p)
        p.start()
            
    for p in processes:
        p.join()
            
main()

11.3 Programmazione asincrona

La programmazione asincrona utilizzando asyncio permette di eseguire compiti in parallelo senza bloccare il thread principale. Anche se non aggira il GIL nel vero senso della parola, permette di utilizzare in modo efficiente il tempo di attesa per eseguire altri compiti.

Esempio:


import asyncio

async def main():
    await asyncio.sleep(1)
    print('Hello')
            
asyncio.run(main())

11.4 Utilizzo di librerie con gestione dei thread propria

Alcune librerie, come NumPy e SciPy, sono scritte in C e utilizzano meccanismi di gestione dei thread propri, permettendo loro di aggirare il GIL e di sfruttare efficacemente i processori multi-core per i calcoli.

In effetti, questa è una delle principali ragioni del successo di Python, per quanto lento possa essere. Tutti i calcoli complessi sono riscritti in linguaggi C/C++ ed eseguiti su tutti i core del processore o addirittura sui core della scheda grafica. E sulle moderne schede grafiche ci sono migliaia di core.

Risulta che non importa più quanto sia veloce o lento il linguaggio, se tutti i calcoli che richiedono molte risorse vengono eseguiti da librerie esterne o addirittura spostati in data center remoti.

11.5 Esecuzione di calcoli al di fuori dell'interprete Python

L'uso di estensioni in C/C++ o altri linguaggi che possono eseguire calcoli al di fuori dell'interprete Python e poi restituire il risultato. Questo permette di evitare di bloccare il GIL durante l'esecuzione di calcoli intensivi.

Esempio di utilizzo di Cython:


# esempio.pyx

def compute(int n):
    cdef int i, result = 0
    for i in range(n):
        result += i
    return result

Compilazione e utilizzo:


cythonize -i example.pyx

import example
print(example.compute(1000000))
1
Опрос
Asincronicità,  26 уровень,  4 лекция
недоступен
Asincronicità
Asincronicità
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION