Voyons voir:
>>> 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
Il ne semble pas qu'ils sont atomiques: les valeurs de x et y pourrait être changé par un autre fil entre les bytecodes LOAD_GLOBAL
, avant ou après le ROT_TWO
, et entre les octets STORE_GLOBAL
.
Si vous voulez échanger deux variables atomiquement, vous aurez besoin d'un verrou ou d'un mutex.
Pour ceux qui désirent une preuve empirique:
>>> 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
Pourquoi? GIL? Le démontage ne suggère pas d'atomicité (voir la réponse de @ jemfinch). – kennytm
(BTW, le commentaire ci-dessus n'est * pas * une question rhétorique.) – kennytm
@Kenny: c'était un malentendu de ma part que la façon dont le déballage de tuple fonctionnait au niveau bas. – voyager