Sécurité des threads dans le dictionnaire Python

105

J'ai une classe qui contient 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 j'utilise 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ûr ou dois-je utiliser un verrou avant d'appeler addOrder?

nmat
la source
2
comment pourrait-il y avoir un problème lorsque chaque thread écrit sur une clé différente de toute façon.
Jochen Ritzel
64
@Jochen: selon la manière dont les dictionnaires sont implémentés, beaucoup de choses pourraient mal tourner. C'est une question très raisonnable.
Ned Batchelder

Réponses:

95

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

Votre code doit être sûr. Gardez à l'esprit: un verrou ici n'ajoutera presque pas de frais généraux et vous donnera la tranquillité d'esprit.

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

Ned Batchelder
la source
6
Voici le pourquoi / comment faire d'effbot.org sur l' implémentation d'un verrou
hobs
1
Devrait envisager une opération unique par rapport aux opérations composites, telles que get-add-set .
andy
5
Le problème est que lorsque je lis / écris fréquemment ce dict, cette tranquillité d'esprit me coûtera cher.
Shihab Shahriar Khan
2
"une serrure ici n'ajoutera presque pas de frais généraux": pourquoi?
max
32

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 sûr contre les accès simultanés.


la source
25
Ce n'est pas une fonctionnalité de Python, mais de cpython .
phihag
8
C'est vrai, mais si je comprends bien, les éléments intégrés dans Jython et IronPython sont également thread-safe même sans l'utilisation du GIL (et l'hirondelle à vide, si jamais elle émerge, propose également de supprimer le GIL). J'ai supposé que puisqu'il n'avait pas spécifié l'interpréteur qu'il utilisait, il voulait dire en CPython.
1
Correct dans le cas de Jython: jython.org/jythonbook/en/1.0
Evgeni Sergeev
9

Le guide de style de Google déconseille de s'appuyer sur l'atomicité de dict

Expliqué plus en détail sur: L'affectation de variable Python est-elle atomique?

Ne vous fiez pas à l'atomicité des types intégrés.

Alors que les types de données intégrés à Python tels que les dictionnaires semblent avoir des opérations atomiques, il existe des cas secondaires où ils ne sont pas atomiques (par exemple, si __hash__ou __eq__sont implémentés en tant que méthodes Python) et leur atomicité ne doit pas être invoquée. Vous ne devez pas non plus vous fier à l'affectation de variables atomiques (car cela dépend à son tour des dictionnaires).

Utilisez le Queuetype de données File d'attente du module comme moyen préféré de communiquer des données entre les threads. Sinon, utilisez le module de thread et ses primitives de verrouillage. Découvrez comment utiliser correctement les variables de condition afin de pouvoir les utiliser threading.Conditionau 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, donc la performance de l'utilisation d'un verrou sera négligeable. Les heures passées à rechercher des bogues dans une base de code complexe seront beaucoup plus coûteuses lorsque ces détails d'implémentation CPython changent un jour.

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