¿Se aplica lo mismo a los diccionarios? ¿O es un diccionario una colección de variables?
Vamos a ser más general:
¿Qué significa "operación atómica" significa?
De Wikipedia:
En la programación concurrente, una operación (o conjunto de operaciones) es atómica, linealizable, indivisibles o ininterrumpible si aparece a la resto del sistema que se produzca instantáneamente. Atomicity es una garantía de de aislamiento de los procesos concurrentes .
¿Qué significa esto en Python?
Esto significa que cada instrucción de bytecode es atómica (al menos para Python < 3.2, antes de la nueva GIL).
¿Por qué es eso ???
Porque Python (CPython) usa un Global Interpreter Lock (GIL). El intérprete CPython usa un bloqueo para asegurarse de que solo se ejecuta un hilo en el intérprete a la vez, y utiliza un "intervalo de comprobación" (ver sys.getcheckinterval()
) para saber cuántas instrucciones de bytecode ejecutar antes de cambiar entre hilos (por defecto establecido en 100)
¿Y ahora qué significa esto?
Significa que las operaciones que se pueden representar con solo una instrucción de bytecode son atómicas. Por ejemplo, incrementando una variable es no atómica, ya que la operación se realiza en tres instrucciones de código de bytes:
>>> import dis
>>> def f(a):
a += 1
>>> dis.dis(f)
2 0 LOAD_FAST 0 (a)
3 LOAD_CONST 1 (1) <<<<<<<<<<<< Operation 1 Load
6 INPLACE_ADD <<<<<<<<<<<< Operation 2 iadd
7 STORE_FAST 0 (a) <<<<<<<<<<<< Operation 3 store
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
¿Qué pasa con los diccionarios ??
Algunas operaciones son atómicas; por ejemplo, esta operación es atómica:
d[x] = y
d.update(d2)
d.keys()
Vea usted mismo:
>>> def f(d):
x = 1
y = 1
d[x] = y
>>> dis.dis(f)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 1 (x)
3 6 LOAD_CONST 1 (1)
9 STORE_FAST 2 (y)
4 12 LOAD_FAST 2 (y)
15 LOAD_FAST 0 (d)
18 LOAD_FAST 1 (x)
21 STORE_SUBSCR <<<<<<<<<<< One operation
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
Ver this entender lo que hace STORE_SUBSCR.
Pero como se ve, no es totalmente cierto, porque esta operación:
...
4 12 LOAD_FAST 2 (y)
15 LOAD_FAST 0 (d)
18 LOAD_FAST 1 (x)
...
puede hacer toda la operación no atómica. ¿Por qué? Digamos que la variable x también puede ser cambiada por otro hilo ... o que quiere que otro hilo borre su diccionario ... podemos nombrar muchos casos cuando puede salir mal, ¡así que es complicado! Y aquí aplicaremos Murphy's Law: "Cualquier cosa que pueda salir mal, saldrá mal".
¿Y ahora qué?
Si aún desea compartir variables entre el hilo, utilice una cerradura:
import threading
mylock = threading.RLock()
def atomic_operation():
with mylock:
print "operation are now atomic"
hecho.Y debería thread N AND M modificaría los datos ['a'] que sucederían, pero ¿qué pasa si el hilo N modifica los datos ['a'] y el hilo M modifica los datos ['b']? ¿Eso todavía pasaría? ¿Y qué se puede hacer sin bloquear el diccionario? – skerit
@skerit: Como escribí, no. No interfieren entre sí. Por supuesto, no puedes estar seguro de que nunca se superpongan si comparten el diccionario ... – delnan
Oh, sí, ya veo. "una ranura en un diccionario". Entonces solo tengo que bloquear el diccionario cuando agregue o elimine una clave, ya que eso causaría excepciones cuando algo se iterara sobre ella. – skerit