7

シーケンスの解凍はアトミックですか?例えば:

(a, b) = (c, d)

私はそうではないという印象を受けています。

編集:マルチスレッドのコンテキストでの原子性、つまり、以前のアトムのように、ステートメント全体が分割できないかどうかを意味しました。

4

2 に答える 2

8

これは1つの操作です。右側の式は、左側の割り当てが適用される前に評価されます。

>>> 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        

ただし、通常の割り当ては常に少なくとも2つのオペコード(1つは右辺の式用、もう1つは結果の格納用)になるため、Pythonでは一般に割り当てはアトミックではありません。シーケンスのアンパックも例外ではありません。

于 2012-11-30T17:04:04.023 に答える
6

次のスクリプトを使用してテストされた、マルチスレッド環境では明らかにアトミックではありません。

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を使用してテストされています。各バージョンで、このスクリプトは「アトミックではありません」と出力し、1秒以内に終了しました。

于 2012-11-30T17:26:01.663 に答える