Không được tính vào số x += 1
là an toàn chỉ. Dưới đây là an example nơi nó không hoạt động (xem bình luận Josiah Carlson):
import threading
x = 0
def foo():
global x
for i in xrange(1000000):
x += 1
threads = [threading.Thread(target=foo), threading.Thread(target=foo)]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join()
print(x)
Nếu bạn tháo rời foo
:
In [80]: import dis
In [81]: dis.dis(foo)
4 0 SETUP_LOOP 30 (to 33)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_CONST 1 (1000000)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 16 (to 32)
16 STORE_FAST 0 (i)
5 19 LOAD_GLOBAL 1 (x)
22 LOAD_CONST 2 (1)
25 INPLACE_ADD
26 STORE_GLOBAL 1 (x)
29 JUMP_ABSOLUTE 13
>> 32 POP_BLOCK
>> 33 LOAD_CONST 0 (None)
36 RETURN_VALUE
Bạn thấy rằng có một LOAD_GLOBAL
để lấy giá trị của x
, có một số INPLACE_ADD
và sau đó là STORE_GLOBAL
.
Nếu cả hai chủ đề LOAD_GLOBAL
liên tiếp, thì cả hai có thể tải cùng giá trị của x
. Sau đó, cả hai đều tăng lên cùng một số và lưu trữ cùng một số. Vì vậy, công việc của một chủ đề sẽ ghi đè tác phẩm của một chủ đề khác. Đây không phải là chủ đề an toàn.
Như bạn có thể thấy, giá trị cuối cùng của x
sẽ là 2000000 nếu chương trình là thread-an toàn, nhưng thay vào đó bạn hầu như luôn luôn có được một số ít hơn 2000000.
Nếu bạn thêm một khóa, bạn sẽ có được "mong đợi" câu trả lời:
import threading
lock = threading.Lock()
x = 0
def foo():
global x
for i in xrange(1000000):
with lock:
x += 1
threads = [threading.Thread(target=foo), threading.Thread(target=foo)]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join()
print(x)
mang
2000000
Tôi nghĩ lý do tại sao đoạn code bạn được đăng không trưng bày một vấn đề:
for i in range(1000):
t = threading.Thread(target = worker)
threads.append(t)
t.start()
là vì worker
của bạn hoàn toàn như vậy darn nhanh chóng so với thời gian cần thiết để đẻ trứng một chủ đề mới mà trong thực tế có không có sự cạnh tranh giữa các chủ đề. Trong ví dụ của Josiah Carlson ở trên, mỗi sợi tiêu tốn một lượng thời gian đáng kể trong foo
làm tăng cơ hội va chạm sợi.
Vì GIL tôi đoán – wim
Cụ thể, CPython thực hiện. – Amber
@ Giống như những hoạt động nào là nguyên tử khi sử dụng GIL? – remykits