2012-05-15 9 views
5

Tengo un diccionario actualizado por un hilo, y en otro hilo me gustaría iterar sobre sus valores. Normalmente utilizaría un bloqueo, pero este código es muy crítico para el rendimiento, y quiero evitar eso si es posible.¿Se puede iterar un diccionario modificado por otro hilo sin generar excepciones?

Una característica especial de mi caso es que no me importa la corrección absoluta del iterador; si pierde las entradas que se eliminaron después de que comenzó la iteración, o recoge las que se agregaron después, está bien. Solo exijo que no genere ningún tipo de excepción de 'tamaño de diccionario modificado durante la iteración'.

Dada esta restricción relajada en la corrección, ¿hay una forma eficiente de iterar el diccionario sin usar un bloqueo?

Nota: Soy consciente de que keys() es threadsafe en Python 2.x, pero como ese comportamiento ha cambiado en 3.x, quiero evitarlo.

+0

¿Qué pasa si 'sólo lo hacen'? –

+3

Cuando se trata de simultaneidad, prefiero trabajar con hechos que con experimentos aleatorios. – DNS

+1

Teniendo en cuenta los efectos del Global Interpreter Lock, tener un bloqueo alrededor de su dict podría no ser tan caro como cree (ya que sus dos hilos de ejecución no se ejecutarán al mismo tiempo). – NPE

Respuesta

4

Sin experiencia personal con esto, pero leí esto hace algún tiempo: 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

dos cosas:

  1. vertedero de las teclas en un queue y leer que con seguridad.
  2. El código crítico para el rendimiento probablemente no debería estar usando subprocesos de Python.
+0

Las colas se bloquean internamente, y tienden a tener un rendimiento significativamente peor que el simple uso de un bloqueo directamente. Tal vez tengas razón acerca de no utilizar subprocesos de Python, pero esa decisión se basa en una serie de otras limitaciones y no es relevante para la pregunta. – DNS

3

Me gustaría considerar el uso de un bloqueo de tiempo suficiente para recuperar los valores que desee para repetir:

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

O bien, puede probarlo sin cerradura y coger RuntimeError, y si usted consigue uno , intenta recuperar los valores nuevamente

[editar] A continuación ligeramente reformulado por suggesion de J. F. Sebastián:

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

yo personalmente iría con la cerradura.

+0

puedes hacer 'while True: \ n try: values ​​= list (the_dict.values ​​()) \ n excepto RuntimeError: pass \ n else: break' – jfs

Cuestiones relacionadas