2010-04-12 6 views

Antwort

54

Mal sehen:

>>> x = 1 
>>> y = 2 
>>> def swap_xy(): 
... global x, y 
... (x, y) = (y, x) 
... 
>>> dis.dis(swap_xy) 
    3   0 LOAD_GLOBAL    0 (y) 
       3 LOAD_GLOBAL    1 (x) 
       6 ROT_TWO    
       7 STORE_GLOBAL    1 (x) 
      10 STORE_GLOBAL    0 (y) 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE  

Es scheint nicht, dass sie atomar: die Werte von x und y könnte von einem anderen Thread zwischen geändert werden die LOAD_GLOBAL Bytecodes, vor oder nach dem ROT_TWO und zwischen den STORE_GLOBAL Bytecodes.

Wenn Sie zwei Variablen atomar vertauschen möchten, benötigen Sie eine Sperre oder einen Mutex.

Für all jene, empirischen Beweis:

>>> def swap_xy_repeatedly(): 
... while 1: 
...  swap_xy() 
...  if x == y: 
...  # If all swaps are atomic, there will never be a time when x == y. 
...  # (of course, this depends on "if x == y" being atomic, which it isn't; 
...  # but if "if x == y" isn't atomic, what hope have we for the more complex 
...  # "x, y = y, x"?) 
...  print 'non-atomic swap detected' 
...  break 
... 
>>> t1 = threading.Thread(target=swap_xy_repeatedly) 
>>> t2 = threading.Thread(target=swap_xy_repeatedly) 
>>> t1.start() 
>>> t2.start() 
>>> non-atomic swap detected 
4

Ja, ja wird es.

I stand corrected.

Kragen Sitaker schreibt:

Jemand empfahl das Idiom mit

spam, eggs = eggs, spam 

eine Thread-sichere Swap zu erhalten. Funktioniert das wirklich? (...)
Wenn also dieser Thread irgendwo zwischen dem ersten LOAD_FAST
und dem letzten STORE_FAST die Kontrolle verliert, könnte ein Wert von einem anderen Thread
in "b" gespeichert werden, der dann verloren gehen würde. Es gibt nichts, was dieses
davon abhält zu geschehen, ist dort?

Nein. Im Allgemeinen ist nicht einmal eine einfache Zuweisung zwingend Thread sicher seit Durchführung der Zuweisung kann spezielle Methoden auf ein Objekt aufrufen, die selbst eine Nummer von Operationen erfordern können. Hoffentlich hat das Objekt seine "Zustand" Werte intern gesperrt, aber das ist nicht immer der Fall.

Aber es ist wirklich diktiert, was „Thread-Sicherheit“ bedeutet in einer bestimmten Anwendung, weil meiner Meinung nach dort gibt viele Ebenen der Granularität solcher Sicherheit, so dass es schwierig ist, über „Thread-Sicherheit“ zu sprechen. Über die einzige Sache der Python-Interpreter geht zu geben Sie kostenlos ist, dass ein eingebauter Datentyp sollte sicher von internen Korruption auch mit nativen Threading sein. Mit anderen Worten, wenn zwei Threads haben a=0xff und a=0xff00 wird eine wird bis mit dem einen oder anderen, aber nicht versehentlich 0xffff wie sein könnte möglich in einigen anderen Sprachen enden, wenn ein nicht geschützt.

Mit dieser sagte, Python neigt auch dazu, ausführen in einer solchen Art und Weise, dass Sie kann weg mit einem sehr viel ohne formale Verriegelung, wenn Sie auf dem Rand bereit sind, ein wenig zu leben und implizierte Abhängigkeiten von den tatsächlich verwendeten Objekten. Es gab eine anständige Diskussion in dieser Richtung hier in c.l.p a while back - Suche groups.google.com für die "Kritische Threads und Mutexe" Thread unter andere.

persönlich Ich schließe explizit freigegeben Zustand (oder Verwendung Konstrukte entworfen für den Austausch von geteilten Informationen richtig unter Threads, wie Queue.Queue) in jeder Multi-Threaded-Anwendung. Um meine Meinung ist es der beste Schutz gegen Wartung und Evolution der Straße.

- - David

+1

Warum? GIL? Die Disassemblierung deutet nicht auf Atomizität hin (siehe @ jemfinchs Antwort). – kennytm

+0

(Übrigens, der obige Kommentar ist * nicht * eine rhetorische Frage.) – kennytm

+0

@Kenny: Es war ein Missverständnis meiner Rolle, wie das Tupel-Entpacken auf niedrigem Niveau funktioniert hat. – voyager