2010-07-29 17 views
23

Alcuni hanno affermato che il dizionario Python è thread-safe. Significa che posso o non posso modificare gli elementi in un dizionario mentre lo sto iterando?python dictionary è thread-safe?

risposta

28

I due concetti sono completamente diversi. Thread safety significa che due thread non possono modificare lo stesso oggetto allo stesso tempo, lasciando quindi il sistema in uno stato incoerente.

Detto questo, non è possibile modificare un dizionario durante l'iterazione su di esso. Vedi lo documentation..

Il dizionario p non deve essere mutato durante l'iterazione. È sicuro (dal Python 2.1) a modificare i valori dei tasti mentre si scorre sul dizionario, ma solo fino a quando il set di chiavi non cambia.

+3

Penso che siano correlati. Cosa succede se un thread itera e l'altro modifica il dict? –

13

No. La versione recente di python genererà un'eccezione se si tenta di ripetere su un dizionario che ha cambiato dimensione tra iterazioni.

>>> d={'one':1, 'two':2} 
>>> for x in d: 
... d['three']=3 
... print x 
... 
two 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: dictionary changed size during iteration 

Si noti che non è necessario utilizzare thread per vedere questo

58

Le altre risposte già correttamente indirizzati ciò che è apparentemente la tua domanda effettiva:

significa che posso o non posso modificati gli elementi in un dizionario mentre iterando su di esso?

spiegando che la sicurezza dei thread non ha nulla a che fare con la questione, e in ogni caso, no, non è possibile modificare un dict mentre iterando su di esso.

Tuttavia, il titolo della tua domanda è sulla sicurezza dei thread, e si inizia con:

Alcuni dichiarato che dizionario Python è sicuro filo

Io non so chi gli "alcuni" lo sono, ma, se lo affermassero (piuttosto che fraintendere quello che hanno affermato ;-) senza pesanti qualifiche, si sbagliano.

Alcune operazioni, quelle che non alterano il mazzo di chiavi nella dict, capita di essere thread-safe in implementazioni CPython attuali - ma si dovrebbe non contare su questo, a meno che non si controlla rigorosamente la Versione di Python con cui verrà eseguito il codice, poiché tale sicurezza dei thread non è garantita dalle specifiche del linguaggio di Python e quindi altre implementazioni, incluse le versioni future di CPython, potrebbero non offrirlo.

Se ogni thread è solo "in lettura" del dict (indicizzazione, looping su di esso, ecc.) E nessun thread esegue alcuna assegnazione o eliminazione su di esso, allora tale situazione è sicura nelle attuali implementazioni di CPython; infatti, se qualche thread assegna un nuovo valore a una chiave che era già presente, questo è anche sicuro per i thread (altri thread potrebbero vedere il valore precedente per quella chiave, o il successivo, a seconda di come i thread accadono per cronometrare, ma non ci saranno crash, nessuna situazione di stallo e nessuna apparizione di valori pazzi dal nulla, nelle attuali implementazioni di CPython).

Tuttavia, un'operazione come d[k] += 1 (supponendo k era presente in precedenza, e il suo valore a number) è non propriamente sicura filo (non più di quanto altro caso di +=!) Perché può essere visto come d[k] = d[k] + 1 - - potrebbe accadere che due thread in una condizione di competizione leggano entrambi il vecchio valore di d[k], quindi lo incrementano di uno e memorizzano lo stesso nuovo valore nello slot ... quindi l'effetto complessivo è di incrementarlo solo di uno e non di due come normalmente accadrebbe.

Torna alla tua altra domanda ... "solo lettura" il dict, e assegnazione di nuovi valori alle chiavi che già esistevano nella dict, sono anche le cose che si possono fare nel corpo di un ciclo che itera su il dict - non è possibile modificare il set di chiavi nel dict (non è possibile aggiungere alcuna chiave, né rimuovere alcuna chiave), ma è consentita l'operazione specifica di impostare un nuovo valore per una chiave esistente. Le operazioni consentite in questo caso includono += che sarebbe problematico in una situazione di threading. Per esempio:

>>> d = dict.fromkeys(range(5), 0) 
>>> for k in d: d[k] += 1 
... 
>>> d 
{0: 1, 1: 1, 2: 1, 3: 1, 4: 1} 

e questo comportamento è garantita dalla semantica standardizzati di Python, così diverse implementazioni del linguaggio dovrebbero preservarla.

+0

Prima hai detto "Se ogni thread è solo" leggendo "il dict (indicizzandolo, eseguendolo in loop, ecc.) E ** nessun thread esegue assegnazioni o cancellazioni su di esso, allora quella situazione è sicura nelle attuali implementazioni di CPython ** ", e alla fine hai detto" l'operazione specifica di ** l'impostazione di un nuovo valore per una chiave esistente è consentita ... e questo comportamento è garantito dalla semantica standardizzata di Python **, quindi tutte le implementazioni del linguaggio dovrebbero preservare esso". Mi sento difficile distinguere i 2 scenari. Potresti per favore elaborare un po 'di più? Grazie in anticipo! – RayLuo