Un échange de variables est-il garanti pour être atomique en python?
En référence au lien suivant: http://docs.python.org/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
Je voulais savoir si ce qui suit:
(x, y) = (y, x)
Sera garanti atomique dans cPython. (x et y sont toutes deux des variables python)
2 réponses
, voyons:
>>> 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 soient atomiques: les valeurs de x et y pourraient être modifiées par un autre thread entre les bytecodes LOAD_GLOBAL
, avant ou après le ROT_TWO
, et entre les bytecodes 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
oui, oui.
Kragen Sitaker écrit:
Quelqu'un a recommandé d'utiliser l'idiome
spam, eggs = eggs, spam
Pour obtenir un échange thread-safe. N'est-ce vraiment le travail? (...)
Donc, si ce thread perd le contrôle n'importe où entre le premier LOAD_FAST
et le dernier STORE_FAST, une valeur pourrait être stockée par un autre thread
en " b " qui serait alors perdu. Il n'y a pas de quoi garder cela
de passe, est-il?Non. En général pas même un simple l'affectation est nécessairement thread safe depuis l'exécution de la mission peut invoquer des méthodes spéciales sur un objet qui eux-mêmes peuvent nécessiter un certain nombre d'exploitation. espérons que l'objet aura verrouillé en interne son "état" valeurs", mais ce n'est pas toujours cas.
Mais c'est vraiment dicté par quoi "sécurité du filetage" signifie Dans un application, parce que à mon esprit là-bas de nombreux niveaux de granularité de ces sécurité il est donc difficile de parler "sécurité du fil". La seule chose l'interpréteur Python va vous donner gratuitement est - ce un intégré type de données doit être sûr de interne corruption même avec threading natif. En d'autres termes, si deux threads ont
a=0xff
eta=0xff00
, a finira par avec l'un ou l'autre, mais pas accidentellement0xffff
comme pourrait l'être possible, dans d'autres langues, si un n'est-ce pas protégé.Cela dit, Python a également tendance à exécuter de telle manière que vous pouvez sortir avec beaucoup sans verrouillage formel, si vous êtes prêt à vivre sur le bord un peu et ont dépendances implicites sur le réel objets en cours d'utilisation . Il y avait un décent discussion dans ce sens ici dans c.l'.p un temps de recherche groups.google.com pour le " Critique sections et mutex " thread among les autres.
Personnellement, Je verrouiller explicitement partagé state (ou utiliser des constructions conçues pour échanger correctement les informations partagées parmi les threads, tels que
Queue.Queue
) dans toute application multi-thread. De mon esprit c'est la meilleure protection contre la maintenance et l'évolution vers le bas route.-- -- David