web-dev-qa-db-fra.com

Thread Safety dans le dictionnaire Python

J'ai une classe qui tient un dictionnaire

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

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

Et je lance 4 threads (un pour chaque restaurant) qui appellent la méthode OrderBook.addOrder. Voici la fonction exécutée par chaque thread:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

Est-ce sécuritaire ou dois-je utiliser un verrou avant d'appeler addOrder?

86
nmat

Les structures intégrées de Python sont thread-safe pour les opérations simples, mais il peut parfois être difficile de voir où une instruction devient réellement plusieurs opérations.

Votre code devrait être en sécurité. Gardez à l'esprit: un verrou n'augmentera presque pas les frais généraux et vous procurera une tranquillité d'esprit.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm contient plus de détails.

78
Ned Batchelder

Oui, les types intégrés sont intrinsèquement thread-safe: http://docs.python.org/glossary.html#term-global-interpreter-lock

Cela simplifie l'implémentation de CPython en rendant le modèle objet (, y compris les types intégrés critiques tels que dict ) implicitement protégé contre les accès concurrents.

28
user626998

Il est à noter que le guide de style de Google déconseille de s'appuyer sur dict atomicity, comme je l'ai expliqué plus en détail à l'adresse suivante: Is Python affectation de variable atomique?

Ne comptez pas sur l'atomicité des types intégrés.

Bien que les types de données intégrés de Python, tels que les dictionnaires, semblent avoir des opérations atomiques, il existe des cas où ils ne sont pas atomiques (par exemple, si __hash__ ou __eq__ sont implémentés comme Python) et leur atomicité ne doit pas être invoquée. Vous ne devez pas non plus vous fier à l’affectation de variables atomiques (puisque cela dépend de dictionnaires).

Utilisez le type de données File d'attente du module Queue comme moyen privilégié de communication des données entre les threads. Sinon, utilisez le module de threading et ses primitives de verrouillage. En savoir plus sur l'utilisation correcte des variables de condition pour pouvoir utiliser threading.Condition au lieu d'utiliser des verrous de niveau inférieur.

Et je suis d’accord avec celui-ci: il y a déjà le GIL dans CPython, de sorte que la performance de l’utilisation d’un verrou sera négligeable. Les heures consacrées à la recherche de bogues dans une base de code complexe lorsque les détails d'implémentation de CPython changent d'un jour sont beaucoup plus coûteuses.