2012-11-30 34 views
5

Trình tự giải nén có phải là nguyên tử không? ví dụ:Trình tự giải nén có phải là nguyên tử không?

(a, b) = (c, d) 

Tôi đang bị ấn tượng là không.

Chỉnh sửa: Tôi có nghĩa là nguyên tử trong ngữ cảnh đa luồng, tức là toàn bộ câu lệnh có thể phân tách được không, như các nguyên tử được sử dụng.

+1

Tôi dưới ấn tượng rằng bạn có lẽ là sự hiểu lầm bởi những gì là * thường được hiểu bởi nguyên tử trong phát triển phần mềm. Bạn đang nói về an toàn thread ở đây, hoặc bạn đang tự hỏi nếu 'a = c' sẽ được thực thi trước' b = d'? –

+0

@MartijnPieters - Nếu OP đã tự hỏi về sau này, OP sẽ rất bối rối tại sao một cái gì đó như '(a, b) = (b, a)' sẽ làm việc để trao đổi các giá trị. Nó phải là một câu hỏi về an toàn luồng. –

+0

@TedHopp: Câu hỏi là quá mơ hồ để gọi điều này, và trong kinh nghiệm của tôi giải nén tuple gây ra rất nhiều nhầm lẫn trong và của chính nó. –

Trả lời

6

Đây là một hoạt động; biểu thức bên phải được đánh giá trước khi việc chuyển nhượng trái được áp dụng:

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

Hoặc, nếu bạn đang nói về môi trường đa luồng, sau đó phân công là không nguyên tử; người phiên dịch đánh giá một giao tuple với một opcode duy nhất, nhưng sử dụng opcodes riêng biệt để sau đó lưu trữ các kết quả vào mỗi biến ảnh hưởng:

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

Tuy nhiên, bình thường assigment sẽ luôn luôn có ít nhất hai opcodes (một cho biểu thức bên phải, một để lưu trữ kết quả), vì vậy trong python nói chung, assigment không phải là nguyên tử. Giải nén trình tự không khác nhau.

+1

Tôi nghĩ nó không phải là biểu thức 'nguyên tử'. thậm chí 'j = i + 1' không phải nguyên tử trong các ngôn ngữ cấp cao. Tôi có 'Semaphore' trong python .... Tôi hiểu sai câu hỏi? –

+0

Điều đó không thực sự thiết lập rằng đó là nguyên tử. Câu hỏi đặt ra là liệu 'a' và' b' được gán giá trị của chúng một cách nguyên tử (có nghĩa là, như là một hoạt động không thể tách rời) trong một môi trường đồng thời. Tôi không tin rằng họ là; nghĩa là, nếu '(a, b)' được cho là kết thúc với các giá trị '(200, 2)' trong bước cuối cùng, một luồng khác có thể thấy '(200, 10)' hoặc '(20, 2)'. –

+0

Tôi hiểu sai câu hỏi (hay đúng hơn là, tôi đã chọn để giải thích câu hỏi rất thưa thớt về câu hỏi thường gặp hơn về các nhận thức tuple). Tôi đã cập nhật nó để bao gồm thông tin an toàn luồng. –

4

Chắc chắn không nguyên tử trong một môi trường đa luồng, kiểm tra bằng cách sử dụng kịch bản sau đây:

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 

Tested sử dụng CPython 2.6, 2.7, và 3.2. Trên mỗi phiên bản, tập lệnh này được in 'Không phải nguyên tử' và đã thoát ngay sau một giây.

+1

Bạn đã kiểm tra lại mã opcodes; giải nén là một, nhưng sau đó có hai STCE_FAST opcodes, một cho mỗi biến bị ảnh hưởng. Rất nhiều cơ hội cho một chủ đề khác để gán một cái gì đó khác nhau ở giữa. –

Các vấn đề liên quan