Seguridad de subprocesos en el diccionario de Python

105

Tengo una clase que tiene un diccionario

class OrderBook:
    orders = {'Restaurant1': None,
              'Restaurant2': None,
              'Restaurant3': None,
              'Restaurant4': None}

    @staticmethod
    def addOrder(restaurant_name, orders):
        OrderBook.orders[restaurant_name] = orders

Y estoy ejecutando 4 hilos (uno para cada restaurante) que llaman al método OrderBook.addOrder. Aquí está la función ejecutada por cada hilo:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

¿Es seguro o tengo que usar un candado antes de llamar addOrder?

nmat
fuente
2
¿cómo podría haber un problema cuando cada hilo escribe en una clave diferente de todos modos?
Jochen Ritzel
63
@Jochen: dependiendo de cómo se implementen los dictados, muchos podrían salir mal. Ésta es una pregunta muy razonable.
Ned Batchelder

Respuestas:

95

Las estructuras integradas de Python son seguras para subprocesos para operaciones únicas, pero a veces puede ser difícil ver dónde una declaración realmente se convierte en operaciones múltiples.

Tu código debe estar seguro. Tenga en cuenta: un candado aquí casi no agregará gastos generales y le dará tranquilidad.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm tiene más detalles.

Ned Batchelder
fuente
6
Aquí está el por qué / cómo hacerlo de effbot.org sobre la implementación de un bloqueo
hobs
1
Debe considerar la operación única frente a las operaciones compuestas, como get-add-set .
Andy
5
El problema es que, cuando leo / escribo con frecuencia ese dictamen, la tranquilidad me costará mucho.
Shihab Shahriar Khan
2
"un candado aquí casi no agregará gastos generales": ¿por qué?
máximo
32

Sí, los tipos integrados son inherentemente seguros para subprocesos: http://docs.python.org/glossary.html#term-global-interpreter-lock

Esto simplifica la implementación de CPython al hacer que el modelo de objetos ( incluidos los tipos integrados críticos como dict ) sea implícitamente seguro contra el acceso concurrente.


fuente
25
Esta no es una característica de Python, sino de cpython .
phihag
8
Es cierto, pero según tengo entendido, las funciones integradas en Jython y IronPython también son seguras para subprocesos incluso sin el uso de GIL (y el trago sin carga, en caso de que surja, propone eliminar también GIL). Supuse que, dado que no especificó el intérprete que estaba usando, se refería a CPython.
1
Correcto en el caso de Jython: jython.org/jythonbook/en/1.0/…
Evgeni Sergeev
9

La guía de estilo de Google desaconseja confiar en dict atomicity

Explicado con más detalle en: ¿Es atómica la asignación de variables de Python?

No confíe en la atomicidad de los tipos integrados.

Si bien los tipos de datos integrados de Python, como los diccionarios, parecen tener operaciones atómicas, hay casos extremos en los que no son atómicos (por ejemplo, si __hash__ o __eq__se implementan como métodos de Python) y su atomicidad no debe confiarse en ella. Tampoco debe confiar en la asignación de variables atómicas (ya que esto a su vez depende de los diccionarios).

Utilice el Queuetipo de datos Cola del módulo como la forma preferida de comunicar datos entre subprocesos. De lo contrario, utilice el módulo de subprocesamiento y sus primitivas de bloqueo. Obtenga información sobre el uso adecuado de las variables de condición para que pueda usar en threading.Conditionlugar de usar bloqueos de nivel inferior.

Y estoy de acuerdo con este: ya existe el GIL en CPython, por lo que el impacto en el rendimiento de usar un Lock será insignificante. Mucho más costosas serán las horas dedicadas a la búsqueda de errores en una base de código compleja cuando esos detalles de implementación de CPython cambien algún día.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente