valor - que es id en python
¿Se garantiza que un intercambio variable sea atómico en python? (2)
Veamos:
>>> 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
No parece que sean atómicos: los valores de x y y podrían cambiarse por otro subproceso entre los LOAD_GLOBAL
byte LOAD_GLOBAL
, antes o después de ROT_TWO
, y entre los STORE_GLOBAL
byte STORE_GLOBAL
.
Si desea cambiar dos variables atómicamente, necesitará un bloqueo o un mutex.
Para aquellos que desean evidencia empírica:
>>> 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
Con referencia al siguiente enlace: http://docs.python.org/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
Quería saber si lo siguiente:
(x, y) = (y, x)
Se garantizará atómico en cPython. (X y Y son ambas variables de Python)
Sí, sí lo hará.
Kragen Sitaker escribe:
Alguien recomendó usar el modismo
spam, eggs = eggs, spam
para obtener un intercambio seguro de hilo. ¿Esto realmente funciona? (...)
Entonces, si este hilo pierde control en cualquier lugar entre el primer LOAD_FAST
y el último STORE_FAST, un valor podría ser almacenado por otro hilo
en "b" que luego se perderá. No hay nada que guarde esto.
de suceder, ¿hay?Nop. En general, ni siquiera una asignación simple es necesariamente segura para subprocesos, ya que realizar la asignación puede invocar métodos especiales en un objeto que a su vez puede requerir varias operaciones. Esperemos que el objeto haya bloqueado internamente sus valores de "estado", pero ese no es siempre el caso.
Pero realmente está dictado por lo que significa "seguridad de subprocesos" en una aplicación en particular, porque en mi opinión hay muchos niveles de granularidad de tal seguridad, por lo que es difícil hablar de "seguridad de subprocesos". Lo único que el intérprete de Python le dará de forma gratuita es que un tipo de datos integrado debe estar a salvo de la corrupción interna, incluso con el enrutamiento nativo. En otras palabras, si dos hilos tienen
a=0xff
ya=0xff00
, a terminará con uno u otro, pero no accidentalmente con0xffff
como podría ser posible en algunos otros idiomas si a no está protegido.Dicho esto, Python también tiende a ejecutarse de tal manera que puedes salirte con la tuya sin un bloqueo formal, si estás dispuesto a vivir un poco al límite y tienes dependencias implícitas en los objetos reales en uso . Hubo una discusión decente a lo largo de esas líneas aquí hace un tiempo: busca en groups.google.com el hilo de "Secciones críticas y exclusiones mutuas", entre otros.
Personalmente, bloqueo explícitamente el estado compartido (o uso constructos diseñados para intercambiar información compartida correctamente entre subprocesos, como
Queue.Queue
) en cualquier aplicación multiproceso. En mi opinión, es la mejor protección contra el mantenimiento y la evolución en el futuro.- - David