序列解包是原子操作吗?例如:
(a, b) = (c, d)
我认为它不是原子性的。编辑:我指的是在多线程的情况下的原子性,即整个语句是否像原子一样不可分割。请注意,上述内容中保留了HTML标记。
序列解包是原子操作吗?例如:
(a, b) = (c, d)
这是一个操作,右侧的表达式在左侧赋值之前被评估:
>>> a, b = 10, 20
>>> a, b
(10, 20)
>>> b, a = a, b
>>> a, b
(20, 10)
>>> a, b = a*b, a/b
>>> a, b
(200, 2)
如果你在谈论多线程环境,那么赋值就不是原子性的;解释器使用单个操作码来评估元组赋值,但使用单独的操作码将结果存储到每个受影响的变量中:
>>> def t(self): a,b=20,20
...
>>> dis.dis(t)
1 0 LOAD_CONST 2 ((20, 20))
3 UNPACK_SEQUENCE 2
6 STORE_FAST 1 (a)
9 STORE_FAST 2 (b)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
a
和b
的值。我不认为它们是;也就是说,如果(a, b)
应该在最后一步结束时具有值(200, 2)
,则另一个线程可能会看到(200, 10)
或(20, 2)
。 - Ted Hopp在多线程环境下绝对不是原子的,使用以下脚本进行测试:
import threading
a, b = 10, 10
finished = False
def thr():
global finished
while True:
# if sequence unpacking and assignment is atomic then (a, b) will always
# be either (10, 10) or (20, 20). Could also just check for a != b
if (a, b) in [(10, 20), (20, 10)]:
print('Not atomic')
finished = True
break
t = threading.Thread(target=thr)
t.start()
while True:
for i in range(1000000):
a, b = 20, 20
a, b = 10, 10
if finished:
t.join()
break
本脚本在 CPython 2.6、2.7 和 3.2 上测试通过。在每个版本上,该脚本都打印“Not atomic”,并在不到一秒钟内退出。
a = c
是否会在b = d
之前执行? - Martijn Pieters(a, b) = (b, a)
这样的交换值的操作会让OP感到非常困惑。这一定是关于线程安全的问题。 - Ted Hopp