2012-05-15 11 views
5

Ho un dizionario aggiornato da un thread e in un altro thread vorrei ripetere i suoi valori. Normalmente userei un lucchetto, ma questo codice è molto critico per le prestazioni, e voglio evitarlo se possibile.Si può iterare un dizionario modificato da un altro thread senza generare eccezioni?

Una particolarità del mio caso è che non mi interessa la correttezza assoluta dell'iteratore; se manca le voci che sono state rimosse dopo l'avvio dell'iterazione, o raccoglie quelle aggiunte in seguito, va bene. Richiedo solo che non generi alcun tipo di eccezione "dimensione dizionario modificata durante l'iterazione".

Dato questo vincolo rilassato sulla correttezza, esiste un modo efficace per iterare il dizionario senza utilizzare un blocco?

Nota: sono a conoscenza del fatto che keys() è thread-safe in Python 2.x, ma poiché tale comportamento è stato modificato in 3.x, voglio evitarlo.

+0

Cosa succede se si 'basta farlo'? –

+3

Quando parliamo di concorrenza, preferirei lavorare sui fatti piuttosto che sugli esperimenti casuali. – DNS

+1

Tenendo presente gli effetti del Global Interpreter Lock, avere un blocco attorno al tuo dict potrebbe non essere costoso come pensi (dato che i tuoi due thread non verranno eseguiti contemporaneamente). – NPE

risposta

4

Nessuna esperienza personale con questo, ma ho letto questo qualche tempo fa: http://www.python.org/dev/peps/pep-3106/

These operations are thread-safe only to the extent that using them in a thread-unsafe way may cause an exception but will not cause corruption of the internal representation.

As in Python 2.x, mutating a dict while iterating over it using an iterator has an undefined effect and will in most cases raise a RuntimeError exception. (This is similar to the guarantees made by the Java Collections Framework.)

2

due cose:

  1. discarica le chiavi in ​​un queue e letto che in modo sicuro.
  2. Il codice critico delle prestazioni probabilmente non dovrebbe utilizzare i thread Python.
+0

Le code si bloccano internamente e tendono ad avere prestazioni significativamente peggiori rispetto all'utilizzo diretto di un lucchetto. Forse hai ragione a non usare i thread Python, ma quella decisione si basa su una serie di altri vincoli e non è pertinente alla domanda. – DNS

3

vorrei considerare l'utilizzo di un blocco abbastanza a lungo per recuperare i valori che si desidera iterare:

with lock: 
    values = the_dict.values() # python 2 
    # values = list(the_dict.values()) # python 3 
for value in values: 
    # do stuff 

Oppure, si potrebbe provare senza una serratura e prendere RuntimeError, e se si ottiene uno , prova a recuperare nuovamente i valori.

[modifica] Sotto leggermente riformulato per suggesion di J.F. Sebastian:

while True: 
    try: 
     values = list(the_dict.values()) 
     break 
    except RuntimeError: 
     pass 

Io personalmente andrei con la serratura.

+0

si potrebbe fare 'while True: \ n provare: values ​​= list (the_dict.values ​​()) \ n tranne RuntimeError: pass \ n else: break' – jfs

Problemi correlati