Thread Safety no dicionário Python

105

Eu tenho uma aula que contém um dicionário

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

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

E estou executando 4 threads (um para cada restaurante) que chamam o método OrderBook.addOrder. Aqui está a função executada por cada thread:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

É seguro ou preciso usar uma fechadura antes de ligar addOrder?

nmat
fonte
2
como poderia haver um problema quando cada thread grava em uma chave diferente de qualquer maneira.
Jochen Ritzel
63
@Jochen: dependendo de como os dictos são implementados, muitos podem dar errado. Esta é uma pergunta muito razoável.
Ned Batchelder

Respostas:

95

As estruturas integradas do Python são thread-safe para operações únicas, mas às vezes pode ser difícil ver onde uma instrução realmente se torna várias operações.

Seu código deve estar seguro. Lembre-se: um bloqueio aqui quase não adicionará sobrecarga e proporcionará tranquilidade.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm tem mais detalhes.

Ned Batchelder
fonte
6
Aqui está o porquê / como fazer do effbot.org sobre a implementação de um bloqueio
hobs
1
Deve-se considerar a operação única versus operações compostas, como get-add-set .
Andy
5
O problema é que, quando estou freqüentemente lendo / escrevendo esse ditado, essa paz de espírito vai me custar muito.
Shihab Shahriar Khan
2
"um bloqueio aqui quase não adicionará sobrecarga": por que isso?
máx.
32

Sim, os tipos integrados são inerentemente thread-safe: http://docs.python.org/glossary.html#term-global-interpreter-lock

Isso simplifica a implementação do CPython, tornando o modelo de objeto ( incluindo tipos integrados críticos, como dict ) implicitamente seguro contra acesso simultâneo.


fonte
25
Este não é um recurso do Python, mas do cpython .
phihag
8
É verdade, mas pelo que entendi, os built-ins em Jython e IronPython também são thread-safe, mesmo sem o uso do GIL (e engolir sem carga, caso surja, propõe acabar com o GIL também). Presumi que, uma vez que ele não especificou o intérprete que estava usando, ele quis dizer em CPython.
1
Correto no caso de Jython: jython.org/jythonbook/en/1.0/…
Evgeni Sergeev
9

O guia de estilo do Google desaconselha confiar na atomicidade de dict

Explicado com mais detalhes em: A atribuição de variável do Python é atômica?

Não confie na atomicidade dos tipos integrados.

Embora os tipos de dados integrados do Python, como dicionários, pareçam ter operações atômicas, há casos em que eles não são atômicos (por exemplo, se __hash__ou__eq__ são implementados como métodos Python) e sua atomicidade não deve ser considerada. Você também não deve confiar na atribuição de variáveis ​​atômicas (já que isso, por sua vez, depende de dicionários).

Use o Queuetipo de dados Fila do módulo como a forma preferencial de comunicar dados entre threads. Caso contrário, use o módulo de threading e seus primitivos de bloqueio. Aprenda sobre o uso adequado de variáveis ​​de condição para que você possa usar em threading.Conditionvez de usar bloqueios de nível inferior.

E eu concordo com este: já existe o GIL no CPython, então o impacto no desempenho do uso de um Lock será insignificante. Muito mais caras serão as horas gastas na caça de bugs em uma base de código complexa quando os detalhes de implementação do CPython mudarem um dia.

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