2009-08-18 5 views
145

Che cos'è un blocco dell'interprete globale e perché è un problema?Che cos'è un blocco dell'interprete globale (GIL)?

Un sacco di rumore è stato fatto intorno rimuovere il GIL da Python, e mi piacerebbe capire il motivo per cui è così importante. Non ho mai scritto un compilatore né un interprete, quindi non essere frugale con i dettagli, probabilmente avrò bisogno che loro capiscano.

+0

possibile duplicato di [Perché il Global Interpreter Lock?] (Http://stackoverflow.com/questions/265687/why-the-global-interpreter-lock) –

risposta

144

GIL di Python è destinato a serializzare l'accesso alle parti interne interprete di diversi thread. Sui sistemi multi-core, significa che più thread non possono effettivamente fare uso di più core. (Se il GIL non ha portato a questo problema, la maggior parte delle persone non si preoccuperebbe del GIL - è solo sollevato come un problema a causa della crescente prevalenza di sistemi multi-core.) Se vuoi capirlo in dettaglio, è possibile visualizzare this video oppure guardare this set of slides. Potrebbe essere troppe informazioni, ma poi hai chiesto i dettagli :-)

Si noti che GIL di Python è solo un problema per CPython, l'implementazione di riferimento. Jython e IronPython non hanno un GIL. Come sviluppatore Python, in genere non si incontra GIL a meno che non si stia scrivendo un'estensione C. Gli autori di estensioni C devono rilasciare GIL quando le loro estensioni bloccano l'I/O, in modo che altri thread nel processo Python abbiano la possibilità di essere eseguiti.

Aggiornamento: Link aggiornato al video per puntare su Youtube, poiché il precedente collegamento blip.tv era marcito.

+31

Buona risposta: in pratica significa che i thread in Python sono utili solo per bloccare I/O; la tua app non andrà mai al di sopra del core 1 CPU di utilizzo del processore –

+5

"Come sviluppatore Python, in genere non incontri GIL a meno che tu non stia scrivendo un'estensione C" - potresti non sapere quale sia la causa del tuo multi-thread il codice in esecuzione a ritmo di lumache è il GIL, ma sentirai sicuramente i suoi effetti. Mi stupisce ancora che sfruttare i vantaggi di un server 32-core con Python significa che ho bisogno di 32 processi con tutto il sovraccarico associato. – Basic

+5

@PaulBetts: non è vero. È probabile che il codice critico delle prestazioni utilizzi già estensioni C che possono e rilasciano GIL ad esempio, moduli 'regex',' lxml', 'numpy'. Cython consente di rilasciare GIL in un codice personalizzato, ad es. ['B2a_bin (data)'] (https://gist.github.com/zed/3526111) – jfs

41

Supponiamo di avere più thread che non in realtà si toccano reciprocamente i dati. Questi dovrebbero essere eseguiti nel modo più indipendente possibile. Se si dispone di un "blocco globale" che è necessario acquisire per chiamare una funzione, può essere considerato un collo di bottiglia. È possibile non trarre molto vantaggio dall'avere più thread in primo luogo.

di metterla in una vera analogia mondo: immaginate 100 sviluppatori che lavorano in una società con una sola tazza di caffè. La maggior parte degli sviluppatori passerebbe il loro tempo ad aspettare caffè invece di programmare.

Niente di tutto questo è Python-specifica - Non conosco i dettagli di ciò che aveva bisogno di un Python GIL per in primo luogo. Tuttavia, si spera che ti abbia dato un'idea migliore del concetto generale.

+0

Ma se invece gli sviluppatori stessero facendo il supporto per il ticketing (scrivendo 2 -minute risposte, poi in attesa di 1 ora), sarebbero tutti abbastanza produttivi, nonostante la singola tazza di caffè. –

1

Wikipedia ha una bella descrizione di un interprete globale bloccare

http://en.wikipedia.org/wiki/Global_Interpreter_Lock

che collega articolo questo bell'articolo che discute la GIL in Python.

http://www.ddj.com/linux-open-source/206103078?pgno=2

+0

Forse è meglio collegare all'inizio di quell'articolo DDJ - http://www.ddj.com/linux-open-source/206103078 –

+5

Grazie, ma ho fatto i miei compiti prima di fare la domanda qui, e ovviamente sono andato a google e wikipedia prima. –

13

Ogni volta che due thread hanno accesso alla stessa variabile avete un problema. In C++, ad esempio, il modo per evitare il problema è definire un blocco mutex per impedire che due thread, diciamo, inseriscano il setter di un oggetto nello stesso momento.

Il multithreading è possibile in python, ma due thread non possono essere eseguiti contemporaneamente a con una granularità più fine rispetto a un'istruzione python. Il thread in esecuzione sta ricevendo un blocco globale chiamato GIL.

Questo significa che se si inizia scrivere del codice multithreading al fine di sfruttare il processore multicore, le prestazioni non migliorerà. La soluzione usuale consiste nell'adozione di processi multipli.

Si noti che è possibile rilasciare GIL se si è all'interno di un metodo che è stato scritto in C, ad esempio.

L'uso di un GIL non è inerente a Python ma ad alcuni dei suoi interpreti, incluso il CPython più comune. (#edited, vedi commento)

La questione GIL è ancora valido in Python 3000.

+0

Stackless ha ancora un GIL. Stackless non migliora il threading (come nel modulo) - offre un diverso metodo di programmazione (coroutine) che tenta di eseguire il side-step del problema, ma richiede funzioni non bloccanti. – jnoller

+0

Buon punto. Grazie per il commento – fulmicoton

+0

E il nuovo GIL in 3.2? – new123456

7

Watch David Beazley dirvi tutto quello che avreste sempre voluto sapere sul GIL.

+3

È un gran chiacchierone - se qualcuno ti convincerà che il GIL fa schifo, è lui. – new123456

+1

il link è morto. :( – szeitlin

+3

David Beazley - Capire il Python GIL - https://www.youtube.com/watch?v=Obt-vMVdM8s –

13

Facciamo capire prima quello che il pitone GIL prevede:

Qualsiasi operazione/istruzione viene eseguita in l'interprete. GIL garantisce che l'interprete sia tenuto da un singolo thread al in un particolare istante di tempo. E il tuo programma python con più thread funziona in un singolo interprete. In ogni particolare istante di tempo, questo interprete è tenuto da un singolo thread. Significa che solo il thread che regge l'interprete è in esecuzione allo in qualsiasi istante di tempo.

Ora, perché è che un problema:

La macchina potrebbe essere avere più core/processori. Inoltre, più core consentono l'esecuzione simultanea di più thread in modo che più thread possano eseguire in qualsiasi momento specifico.. Ma poiché l'interprete è contenuto da un singolo thread, altri thread non stanno facendo nulla anche se hanno accesso a un core. Quindi, non si ottiene alcun vantaggio fornito da più core, perché in qualsiasi istante viene utilizzato solo un singolo core, che è il nucleo utilizzato dal thread attualmente in possesso dell'interprete. Quindi, il tuo programma impiegherà il tempo necessario per eseguirlo come se fosse un programma a thread singolo.

Tuttavia, le operazioni potenzialmente bloccanti o di lunga durata, come I/O, elaborazione immagine e numerazione dei numeri NumPy, si verificano all'esterno di GIL. Tratto da here. Pertanto, per tali operazioni, un'operazione con multithreading sarà ancora più veloce di un'operazione a thread singolo nonostante la presenza di GIL. Quindi, GIL non è sempre un collo di bottiglia.

Modifica: GIL è un dettaglio di implementazione di CPython. PyPy e Jython non hanno GIL, quindi un programma veramente multithread dovrebbe essere possibile in loro, pensavo che non ho mai usato PyPy e Jython e non ne sono sicuro.

+3

** Nota **: PyPy ha il ** GIL **. _Reference_: [http://doc.pypy.org/en/latest/faq.html#does-pypy-have-a-gil-why](http://doc.pypy .org/it/latest/faq.html # does-pypy-have-a-gil-perché). Mentre Ironpython e Jython non hanno GIL. –

+0

In effetti, PyPy ha un GIL, ma IronPython no. – Emmanuel

0

Perché Python (CPython e altri) utilizza la GIL

Da http://wiki.python.org/moin/GlobalInterpreterLock

Nel CPython, il blocco interprete globale, o GIL , è un mutex che impedisce a più thread nativi di eseguire bytecode Python contemporaneamente. Questo blocco è necessario principalmente perché la gestione della memoria di CPython non è thread-safe.

Come rimuoverlo da Python?

Come Lua, forse Python potrebbe avviare più VM, ma Python non lo fa, credo che ci dovrebbero essere altri motivi.

In Numpy o in qualche altra libreria estesa di Python, a volte, il rilascio di GIL su altri thread potrebbe aumentare l'efficienza dell'intero programma.

1

Voglio condividere un esempio dal multithreading del libro per effetti visivi. Quindi ecco una classica situazione di blocco morto

static void MyCallback(const Context &context){ 
Auto<Lock> lock(GetMyMutexFromContext(context)); 
... 
EvalMyPythonString(str); //A function that takes the GIL 
...  
} 

Considerare ora gli eventi nella sequenza risultante in un dead-lock.

╔═══╦════════════════════════════════════════╦══════════════════════════════════════╗ 
║ ║ Main Thread       ║ Other Thread       ║ 
╠═══╬════════════════════════════════════════╬══════════════════════════════════════╣ 
║ 1 ║ Python Command acquires GIL   ║ Work started       ║ 
║ 2 ║ Computation requested     ║ MyCallback runs and acquires MyMutex ║ 
║ 3 ║          ║ MyCallback now waits for GIL   ║ 
║ 4 ║ MyCallback runs and waits for MyMutex ║ waiting for GIL      ║ 
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝ 
4

Python non permette il multi-threading nel vero senso della parola. Ha un pacchetto multi-threading ma se vuoi multi-thread per velocizzare il tuo codice, di solito non è una buona idea usarlo. Python ha un costrutto chiamato Global Interpreter Lock (GIL). GIL si assicura che solo uno dei tuoi "thread" possa essere eseguito in qualsiasi momento. Un thread acquisisce il GIL, fa un po 'di lavoro, quindi passa GIL sul thread successivo. Questo accade molto velocemente, quindi all'occhio umano potrebbe sembrare che i tuoi thread siano eseguiti in parallelo, ma in realtà stanno solo prendendo a turno usando lo stesso core della CPU. Tutto questo passaggio di GIL aggiunge un sovraccarico all'esecuzione. Ciò significa che se vuoi far funzionare il tuo codice più velocemente, usare spesso il pacchetto di threading non è una buona idea.

Ci sono motivi per utilizzare il pacchetto di threading di Python. Se vuoi eseguire alcune cose contemporaneamente, e l'efficienza non è una preoccupazione, allora è assolutamente soddisfacente. Oppure se stai usando un codice che deve aspettare qualcosa (come un qualche IO), allora potrebbe avere molto senso. Ma la libreria di threading non ti consente di utilizzare core CPU aggiuntivi.

Il multi-threading può essere esternalizzato al sistema operativo (tramite multielaborazione), alcune applicazioni esterne che chiamano il codice Python (ad esempio, Spark o Hadoop) o un codice che il codice Python chiama (ad es. potrebbe avere il tuo codice Python chiamare una funzione C che fa le costose cose multi-thread).