Il blocco dellinterprete globale (GIL) sembra essere spesso citato come una delle ragioni principali per cui threading e simili sono un tocco complicato in Python, il che solleva la domanda “Perché è stato fatto in primo luogo?”
Non essendo un programmatore, “non ho idea del motivo per cui potrebbe essere – qual era la logica dietro linserimento del GIL?
Commenti
- L articolo di Wikipedia afferma che ” il GIL può essere una barriera significativa al parallelismo, un prezzo pagato per avere il dinamismo del linguaggio ” , e prosegue dicendo che ” I motivi per utilizzare tale blocco includono: maggiore velocità dei programmi a thread singolo (nessuna necessità di acquisire o rilasciare i blocchi su tutte le strutture di dati separatamente) e facile integrazione delle librerie C che di solito sono non thread-safe. ”
- @RobertHarvey, il dinamismo non ha nulla a che fare con esso. Il problema è la mutazione.
- stackoverflow.com/questions/265687/…
- Può ‘ t aiutare a pensare che, come la mancanza di ‘ Java di valori numerici senza segno, aveva lo scopo di evitare che le persone ‘ non so cosa stanno facendo ‘ sparandosi ai piedi. Sfortunatamente, chiunque sa cosa ‘ sta facendo ottiene un linguaggio carente, il che è un vero peccato perché Python oscilla in tanti altri modi
- @Basic ci deve essere un modo standard per gestire gli array di byte in Java (non ‘ lho usato da molto tempo) per fare calcoli crittografici. Python (ad esempio) ‘ non ha numeri con segno, ma ‘ non proverei nemmeno a eseguire operazioni bit a bit con esso perché ci sono modi migliori.
Risposta
Ci sono diverse implementazioni di Python, ad esempio, CPython, IronPython, RPython, ecc.
Alcuni di loro hanno un GIL, altri no. Ad esempio, CPython ha il GIL:
Da http://en.wikipedia.org/wiki/Global_Interpreter_Lock
Le applicazioni scritte in linguaggi di programmazione con un GIL possono essere progettate per utilizzare processi separati per ottenere il pieno parallelismo, poiché ogni processo ha il proprio interprete e a sua volta ha il proprio GIL.
Vantaggi del GIL
- Maggiore velocità dei programmi a thread singolo.
- Facile integrazione di librerie C che di solito non sono thread-safe.
Perché Python (CPython e altri) usa il GIL
In CPython, il blocco dellinterprete globale, o GIL, è un mutex che impedisce a più thread nativi di eseguire i bytecode Python contemporaneamente. Questo blocco è necessario principalmente perché la gestione della memoria di CPython non è thread-safe.
Il GIL è controverso perché impedisce ai programmi CPython multithread di sfruttare appieno i sistemi multiprocessore in determinate situazioni. Si noti che potenzialmente il blocco o operazioni di lunga durata, come I / O, elaborazione di immagini e numPy crunching, avvengono al di fuori del GIL. Pertanto è solo nei programmi multithread che trascorrono molto tempo allinterno del GIL, interpretando il bytecode CPython, che il GIL diventa un collo di bottiglia.
Python ha un GIL al contrario del blocco a grana fine per diversi motivi:
-
È più veloce nel caso a thread singolo.
-
È più veloce nel caso del multi-thread per i programmi legati a i / o.
-
È più veloce nel caso del multi-thread per i programmi legati alla cpu che lo fanno il loro lavoro ad alta intensità di calcolo nelle librerie C.
-
Rende Estensioni C più facili da scrivere: non ci sarà alcun cambio di thread Python tranne dove permetti che accada (es. tra le macro Py_BEGIN_ALLOW_THREADS e Py_END_ALLOW_THREADS).
-
Rende più facile il wrapping delle librerie C. Non devi preoccuparti della thread-safe. Se la libreria non è thread-safe, tieni semplicemente bloccato il GIL mentre lo chiami.
Il GIL può essere rilasciato dalle estensioni C. La libreria standard di Python rilascia il GIL attorno a ogni chiamata di blocco i / o. Quindi il GIL non ha conseguenze per le prestazioni dei server vincolati a i / o. È quindi possibile creare server di rete in Python utilizzando processi (fork), thread o i / o asincrono, e il GIL non si intrometterà.
Le librerie numeriche in C o Fortran possono essere chiamate in modo simile con il Rilasciato il GIL. Mentre lestensione C attende il completamento di una FFT, linterprete eseguirà altri thread Python.Un GIL è quindi più facile e veloce del bloccaggio a grana fine anche in questo caso. Questo costituisce la maggior parte del lavoro numerico. Lestensione NumPy rilascia il GIL ogni volta che è possibile.
I thread sono solitamente un cattivo modo per scrivere la maggior parte dei programmi server. Se il carico è basso, la foratura è più facile. Se il carico è elevato, è meglio i / o asincrono e la programmazione guidata dagli eventi (ad esempio utilizzando il framework Twisted di Python). Lunica scusa per utilizzare i thread è la mancanza di os.fork su Windows.
Il GIL è un problema se, e solo se, stai facendo un lavoro ad alta intensità di CPU in puro Python. Qui puoi ottenere un design più pulito usando processi e passaggio di messaggi (ad esempio mpi4py). Cè anche un modulo di “elaborazione” in Python cheese shop, che fornisce ai processi la stessa interfaccia dei thread (cioè sostituire threading.Thread con processing.Process).
I thread possono essere utilizzati per mantenere la reattività di una GUI indipendentemente dal GIL. Se il GIL altera le prestazioni (cfr. la discussione sopra), puoi lasciare che il tuo thread generi un processo e attendere che finisca.
Commenti
- Suona come uva acerba per me. Python può ‘ non eseguire correttamente i thread, quindi si inventano ragioni per cui i thread non sono necessari o addirittura non validi. ” Se il caricamento è basso, fo rking è più facile “, sul serio? E il GIL è ” più veloce ” per tutti questi casi solo se insisti a utilizzare il conteggio dei riferimenti GC.
-
s/RPython/PyPy/g
. @MichaelBorgwardt Dare ragioni a favore di GIL è un po il punto della domanda, non è ‘ vero? Anche se sono daccordo sul fatto che alcuni dei contenuti di questa risposta (vale a dire la discussione delle alternative) siano fuori questione. E nel bene e nel male, il ref conteggio è ora quasi impossibile da eliminare – è profondamente radicato nellintera API e base di codice; ‘ è quasi impossibile sbarazzarsene senza riscrivere metà del codice e rompere tutto il codice esterno. - Don ‘ Per dimenticare la libreria
multiprocessing
– standard dalla 2.6. I pool di worker ‘ sono unastrazione eccellente per alcuni semplici tipi di parallelismo. - @alcalde Solo se non ‘ Non sai cosa ‘ stai facendo e / o non ‘ vuoi che i tuoi thread siano in grado di lavorare in modo cooperativo / comunicare. Altrimenti, ‘ è una vera seccatura, soprattutto considerando il sovraccarico del lancio di un nuovo processo su alcuni sistemi operativi. Abbiamo server con 32 core, quindi per utilizzarli completamente in CPython I ‘ d ho bisogno di 32 processi. Questa ‘ non è una ” buona soluzione ” ‘ un trucco per aggirare le ‘ inadeguatezze di CPython.
- Il fatto che i thread esistano su piattaforme diverse da Windows dovrebbe essere una prova sufficiente che il fork non è ‘ t adeguato in ogni situazione.
Risposta
Primo off: Python non ha un GIL. Python è un linguaggio di programmazione. Un linguaggio di programmazione è un insieme di regole e restrizioni matematiche astratte. Non cè nulla nella specifica del linguaggio Python che dica che deve esserci un GIL.
Ci sono molte differenti implementazioni di Python. Alcuni hanno un GIL, altri no.
Una semplice spiegazione per avere un GIL è che scrivere codice simultaneo è difficile. Inserendo un lucchetto gigante attorno al codice, lo costringi a funzionare sempre in serie. Problema risolto!
In CPython, in particolare, un obiettivo importante è rendere facile estendere linterprete con plugin scritti in C. Di nuovo, scrivere codice simultaneo è difficile, quindi garantire che non ci sarà concorrenza, rende più facile scrivere estensioni per linterprete. Inoltre, molte di queste estensioni sono solo sottili involucri di librerie esistenti che potrebbero non essere state scritte tenendo conto della concorrenza.
Commenti
- Questo ‘ è lo stesso argomento della mancanza di tipi numerici senza segno in Java ‘: gli sviluppatori pensano che tutti gli altri siano più stupidi di loro …
- @Basic – che tu ci creda o no, anche quando ‘ non sei davvero, davvero stupido, risulta che avere un linguaggio che fa supposizioni semplificative che significa che non ‘ Non pensare a certe cose per farle funzionare è ancora una cosa utile.CPython è ottimo per certe cose, incluse semplici applicazioni multithread (dove il programma è associato a IO, che molti lo sono, e quindi il GIL non ‘ importa), perché le decisioni di progettazione che hanno preso il GIL la soluzione migliore rende anche la programmazione di queste applicazioni più semplice, in particolare il fatto che supporta operazioni atomiche sulle raccolte .
- @Jules Sì, ‘ è molto utile fino a quando non avrai bisogno di queste capacità. cpython ‘ s ” preferito ” soluzione di ” basta scriverlo in un altro linguaggio come c ++ ” quindi perdi ogni singolo vantaggio di Python. Se ‘ stai scrivendo metà del tuo codice in c ++, perché iniziare da Python? Certo, per piccoli progetti API / glue è ‘ facile e veloce e per ETL ‘ non è secondo a nessuno, ma ‘ non è adatto a tutto ciò che richiede un sollevamento pesante. Come usare Java per parlare con lhardware … ‘ sono quasi comici i cerchi che devi superare.
- @Basic One of Python ‘ e quindi estendere la filosofia di base di CPython ‘ è rendere la tecnologia ” amichevole e facile da usare “. La programmazione parallela senza blocco globale non è questo. Considerando che ci sono molte implementazioni senza GIL, ha senso fornire almeno unimplementazione che ce lha.
- Dici che ” ha senso fornire almeno unimplementazione che ce lha. ” piace ‘ è lovvia conclusione, ma nessun altro linguaggio è ‘ so che ostacola i suoi sviluppatori in questo modo, quindi può ‘ essere così ovvio.
Risposta
Qual è lo scopo di un GIL?
La documentazione CAPI dice questo sullargomento:
Linterprete Python non è completamente thread-safe . Per supportare programmi Python multi-thread, esiste un blocco globale, chiamato blocco dellinterprete globale o GIL, che deve essere mantenuto dal thread corrente prima che possa accedere in sicurezza agli oggetti Python. Senza il blocco, anche le operazioni più semplici potrebbero causare problemi in un programma multi-thread: ad esempio, quando due thread incrementano simultaneamente il conteggio dei riferimenti dello stesso oggetto, il conteggio dei riferimenti potrebbe finire per essere incrementato solo una volta anziché due.
In altre parole, il GIL impedisce la corruzione dello stato. I programmi Python non dovrebbero mai produrre un errore di segmentazione, perché sono consentite solo operazioni sicure per la memoria. Il GIL estende questa garanzia ai programmi multi-thread.
Quali sono le alternative?
Se lo scopo del GIL è quello di proteggere lo stato dalla corruzione, allora unovvia alternativa è bloccare a un grano molto più fine; forse a livello di oggetto. Il problema con questo è che sebbene sia stato dimostrato di aumentare le prestazioni dei programmi multi-thread, ha più overhead e i programmi a thread singolo soffrono di conseguenza.
Commenti
- Sarebbe fantastico consentire a un utente di eseguire un programma con unopzione interprete che sostituisce il gil per un blocco a grana fine e in qualche modo sapere, in sola lettura, se il processo corrente è stato sollevato con o senza gil.
- Nonostante GIL sono riuscito a produrre un errore di segmentazione in un programma multithread a causa di un uso incauto del modulo pyodbc. Pertanto ” non dovrebbe mai produrre un errore di segmentazione ” è un errore.