Thread-Sicherheit in Pythons Wörterbuch

103

Ich habe eine Klasse, die ein Wörterbuch enthält

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

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

Und ich führe 4 Threads aus (einen für jedes Restaurant), die die Methode aufrufen OrderBook.addOrder. Hier ist die Funktion, die von jedem Thread ausgeführt wird:

def addOrders(restaurant_name):

    #creates orders
    ...

    OrderBook.addOrder(restaurant_name, orders)

Ist das sicher oder muss ich vor dem Anruf ein Schloss benutzen addOrder?

nmat
quelle
2
Wie könnte es ein Problem geben, wenn jeder Thread trotzdem auf einen anderen Schlüssel schreibt?
Jochen Ritzel
63
@Jochen: Je nachdem, wie Diktate umgesetzt werden, kann viel schief gehen. Dies ist eine sehr vernünftige Frage.
Ned Batchelder

Antworten:

94

Die in Python integrierten Strukturen sind für einzelne Operationen threadsicher, aber manchmal ist es schwierig zu erkennen, wo eine Anweisung tatsächlich zu mehreren Operationen wird.

Ihr Code sollte sicher sein. Denken Sie daran: Eine Sperre hier verursacht fast keinen Overhead und gibt Ihnen Sicherheit.

http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm enthält weitere Details.

Ned Batchelder
quelle
6
Hier ist das effbot.org Warum-/ Wie-zur Implementierung eines Schlosses
Kochfelder
1
Sollte eine einzelne Operation im Vergleich zu zusammengesetzten Operationen wie get-add-set in Betracht ziehen .
Andy
5
Das Problem ist, wenn ich dieses Diktat häufig lese / schreibe, kostet mich dieser Seelenfrieden viel.
Shihab Shahriar Khan
2
"Eine Sperre hier bringt fast keinen Overhead": Warum ist das so?
Max
31

Ja, integrierte Typen sind von Natur aus threadsicher: http://docs.python.org/glossary.html#term-global-interpreter-lock

Dies vereinfacht die CPython-Implementierung, indem das Objektmodell ( einschließlich kritischer integrierter Typen wie dict ) implizit vor gleichzeitigem Zugriff geschützt wird.


quelle
24
Dies ist keine Funktion von Python, sondern von cpython .
Phihag
8
Es stimmt, aber so wie ich es verstehe, sind die in Jython und IronPython integrierten Funktionen auch ohne die Verwendung der GIL threadsicher (und die unbeladene Schwalbe, falls sie jemals auftauchen sollte, schlägt vor, die GIL ebenfalls zu beseitigen). Ich nahm an, dass er in CPython meinte, da er den von ihm verwendeten Interpreter nicht spezifizierte.
1
Richtig im Fall von Jython: jython.org/jythonbook/en/1.0/…
Evgeni Sergeev
9

Der Styleguide von Google rät davon ab, sich auf diktierte Atomarität zu verlassen

Weitere Erläuterungen unter: Ist die Zuweisung von Python-Variablen atomar?

Verlassen Sie sich nicht auf die Atomizität eingebauter Typen.

Während die in Python integrierten Datentypen wie Wörterbücher atomare Operationen zu haben scheinen, gibt es Eckfälle, in denen sie nicht atomar sind (z. B. wenn __hash__oder __eq__als Python-Methoden implementiert sind) und auf deren Atomizität nicht vertraut werden sollte. Sie sollten sich auch nicht auf die Zuweisung atomarer Variablen verlassen (da dies wiederum von Wörterbüchern abhängt).

Verwenden Sie den QueueWarteschlangendatentyp des Moduls als bevorzugte Methode zur Datenübertragung zwischen Threads. Verwenden Sie andernfalls das Threading-Modul und seine Sperrprimitive. Erfahren Sie mehr über die ordnungsgemäße Verwendung von Bedingungsvariablen, damit Sie threading.ConditionSperren auf niedrigerer Ebene verwenden können.

Und ich stimme diesem zu: Es gibt bereits die GIL in CPython, so dass der Leistungseinbruch bei der Verwendung eines Schlosses vernachlässigbar ist. Viel teurer sind die Stunden, die für die Fehlersuche in einer komplexen Codebasis aufgewendet werden, wenn sich die Details der CPython-Implementierung eines Tages ändern.

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