2010-10-26 13 views
8

Nell'attuale implementazione di CPython, esiste un oggetto noto come "GIL" o "Global Interpreter Lock". È essenzialmente un mutex che impedisce a due thread Python di eseguire il codice Python contemporaneamente. Questo impedisce a due thread di essere in grado di corrompere lo stato dell'interprete Python, ma impedisce anche l'esecuzione di più thread contemporaneamente. In sostanza, se faccio questo:Qual è la versione di GIL di C#?

# Thread A 
some_list.append(3) 
# Thread B 
some_list.append(4) 

non può corrompere la lista, perché in un dato momento, solo uno di questi fili sono in esecuzione, dal momento che devono essere in possesso della GIL a farlo. Ora, gli elementi nell'elenco potrebbero essere aggiunti in un ordine indeterminato, ma il punto è che l'elenco non è danneggiato e verranno aggiunti sempre due elementi.

Quindi, ora C#. C# essenzialmente affronta lo stesso problema di Python, quindi, come C# impedisce questo? Sarei anche interessato ad ascoltare la storia di Java, se qualcuno lo sa.


Precisazione: Mi interessa ciò che accade, senza dichiarazioni di chiusura esplicite, soprattutto alla VM. Sono a conoscenza del fatto che esistono primitive di blocco sia per Java & C#, che esistono anche in Python: GIL non è usato per il codice multi-thread, se non per mantenere l'interprete sano di mente. Sono interessato l'equivalente diretta di quanto sopra, quindi, in C#, se riesco a ricordare abbastanza ... :-)

List<String> s; 
// Reference to s is shared by two threads, which both execute this: 
s.Add("hello"); 
// State of s? 
// State of the VM? (And if sane, how so?) 

Ecco un altro esempio:

class A 
{ 
    public String s; 
} 
// Thread A & B 
some_A.s = some_other_value; 

// some_A's state must change: how does it change? 
// Is the VM still in good shape afterwards? 

Io non sto cercando per scrivere codice C# errato, capisco le dichiarazioni lock. Anche in Python, GIL non ti dà codice magic-multi-thread: devi comunque bloccare le risorse condivise. . Ma la GIL impedisce "VM" di Python dalla corruzione - è questo comportamento che mi interessa

+0

si può essere interessati nella sezione "concorrenza" di questo [confronto di Python e Clojure] (http: //www.bestinclass .dk/index.clj/2009/10/python-vs-clojure-evolving.html), per una discussione su GIL e su come il problema della concorrenza viene gestito in lingue senza GIL. –

+0

La mia comprensione è che si tratta di un compromesso tra quale classe di problemi sarà più onerosa da risolvere. Vedi la mia risposta qui sotto. – pyfunc

risposta

4

Uso del blocco, si dovrebbe fare questo:

lock(some_list) 
{ 
    some_list.Add(3); 
} 

e in filo 2:

lock(some_list) 
{ 
    some_list.Add(4); 
} 

il lock dichiarazione assicura che l'oggetto all'interno del lock dichiarazione, some_list in questo caso, si può accedere da un solo filo per volta. Vedere http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx per ulteriori informazioni.

+0

Potrei, e Python ha istruzioni di blocco simili. Sono più interessato al fatto che i blocchi non vengano eseguiti: è possibile corrompere la VM sottostante? – Thanatos

+0

@Thanatos: non la VM, ma la struttura dei dati. –

+2

Il risultato è che non ci sarà alcuna garanzia di ciò che accadrà. ** non ** corromperà lo stato della VM. Può tuttavia corrompere lo stato dell'istanza su cui si stanno chiamando i metodi. Quando non è specificamente indicato nelle pagine MSDN, la regola generale è che i metodi di istanza devono essere racchiusi in 'lock' ei metodi statici non devono essere racchiusi in' lock'. Il blocco –

11

La maggior parte degli altri linguaggi che supportano la filettatura non hanno un equivalente di Python GIL; richiedono di usare mutex, implicitamente o esplicitamente.

+3

Inoltre, non prenderei mai in considerazione la scrittura di codice multi-thread in una lingua con qualcosa come un GIL. È come un'insegna al neon lampeggiante che dice: "Il multithreading è troppo difficile, ci arrendiamo". –

+6

Non prenderei in considerazione la scrittura di un programma multithread in un linguaggio che non può mantenere la sua struttura di dati di base coerente da sola e fa affidamento sui programmatori per aggiungere i lock ovunque. – piro

+2

Preferisci usare un linguaggio in cui è impossibile che accada più di una cosa alla volta? Questo non è un programma multithread. E no, "aggiungere serrature ovunque" non è l'unica alternativa. –

1

Può essere istruttivo guardare il documentation for the Java equivalent della classe si sta discutendo:

Si noti che questa implementazione non è sincronizzato. Se più thread accedono contemporaneamente a un'istanza ArrayList e almeno uno dei thread modifica l'elenco in modo strutturale, è necessario che sia sincronizzato esternamente a. (Una modifica strutturale è qualsiasi operazione che aggiunge o elimina uno o più elementi, o ridimensiona esplicitamente l'array di supporto, semplicemente impostando il valore di un elemento non è una modifica strutturale.) Ciò è tipicamente ottenuto sincronizzando su qualche oggetto che incapsula naturalmente il elenco. Se non esiste alcun oggetto di questo tipo, l'elenco deve essere "incapsulato" utilizzando il metodo Collections.synchronizedList.Questo è fatto meglio al momento della creazione, per impedire l'accesso non sincronizzato accidentali alla lista:

List list = Collections.synchronizedList(new ArrayList(...)); 

Gli iteratori restituito da iteratore e ListIterator i metodi di questa classe sono fail-fast: se la lista è strutturalmente modificato in qualsiasi momento dopo che l'iteratore è stato creato, in qualsiasi modo, tranne attraverso i metodi di rimozione o aggiunta dell'iter, l'iteratore genererà un valore ConcurrentModificationException. Quindi, di fronte a modifiche simultanee, l'iteratore fallisce rapidamente e in modo pulito, piuttosto che rischiare di comportarsi in modo arbitrario e non deterministico in un tempo indeterminato nel futuro.

Si noti che il comportamento fail-fast di un iteratore non può essere garantito in quanto è, in generale, impossibile fornire garanzie rigide in presenza di modifiche simultanee non sincronizzate. Gli iteratori fail-fast generano ConcurrentModificationException in base al miglior sforzo. Pertanto, sarebbe sbagliato scrivere un programma che dipendesse da questa eccezione per la sua correttezza: il comportamento fail-fast degli iteratori dovrebbe essere usato solo per rilevare i bug.

3

C# non ha un equivalente di GIL in Python.

Anche se si trovano ad affrontare lo stesso problema, i loro obiettivi di progettazione li rendono diverso.

Con GIL, CPython assicura che le operazioni di ricerca come l'aggiunta di un elenco da due thread siano semplici. Il che anche significa che consentirebbe l'esecuzione di un solo thread in qualsiasi momento. Questo rende le liste e i dizionari thread safe. Anche se questo rende il lavoro più semplice e intuitivo, lo rende più difficile sfruttare il multithreading su multicores.

Senza GIL, C# fa il contrario. Assicura che l'onere dell'integrità sia nello sviluppatore del programma ma consente di sfruttare il vantaggio di eseguire più thread contemporaneamente.

Come per uno della discussione -

La GIL in CPython è puramente una scelta progettuale di avere un grande blocco contro un blocco per oggetto e la sincronizzazione per assicurarsi che gli oggetti sono tenuti in uno stato coerente. Consiste in un compromesso - Assegnare tutta la potenza del multithreading .

È stato che la maggior parte dei problemi non soffre di questo svantaggio e ci sono librerie che aiutano a risolvere questo problema esclusivamente quando è richiesto . Ciò significa che per una certa classe di problemi, l'onere di utilizzare il multicore è passato a sviluppatori in modo che il riposo può godere il, intuitivo approccio più semplice .

Nota: Altre implementazioni come IronPython non hanno GIL.

+0

@Daniel DiPaolo: Grazie mille. In qualche modo la citazione non funziona per me quando seleziono un testo e cerco di citarlo. – pyfunc

+0

Strano, beh il segreto è che è solo '>' all'inizio di una linea che impone il blockquote invece della formattazione del codice. Si noti che è ancora possibile eseguire la formattazione del codice all'interno di una citazione di blocco spacciandola appropriatamente con un '>' all'inizio della riga. –

0

Le strutture dati più complesse (ad esempio elenchi) possono essere danneggiate se utilizzate senza il blocco in più thread.

Poiché le modifiche dei riferimenti sono atomiche, un riferimento rimane sempre un riferimento valido.

Ma c'è un problema quando si interagisce con il codice critico di sicurezza. Quindi, qualsiasi Datastructures utilizzati dal codice critical più essere uno dei seguenti:

  • inaccessibile dal codice non attendibile, e bloccati/usato correttamente dal codice di fiducia
  • Immutabile (classe String)
  • Copiato prima dell'uso (parametri ValueType)
  • scritto in codice di fiducia e utilizza bloccaggio interno per garantire uno stato sicuro

ad esempio di codice critica non può fidarsi di un elenco accessibile da codice non attendibile. Se viene passato in un elenco, deve creare una copia privata, eseguire i controlli di precondizione sulla copia e quindi operare sulla copia.

0

ho intenzione di prendere un ipotesi a ciò che la domanda davvero significa ...

In strutture dati Python nelle interprete vengono danneggiati a causa Python sta usando una forma di conteggio di riferimento.

Sia C# che Java utilizzano la garbage collection e infatti do utilizzano un blocco globale quando si esegue una raccolta heap completa.

I dati possono essere contrassegnati e spostati tra "generazioni" senza blocco. Ma per ripulirlo davvero tutto deve finire. Speriamo che si fermi molto brevemente, ma a tempo pieno.

Ecco un link interessante per la raccolta dei rifiuti CLR a partire dal 2007:
http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry

Problemi correlati