因為多線程的時候,線程之間的數據共享,最大的危險是都可以來修改變量例如
import time ,threading balance = 0 def change_it(n): global balance balance = balance +n balance = balance - n def run_thread(n): for i in range(1000000): change_it(n) t1 = threading.Thread(target = run_thread , args = (5,)) t2 = threading.Thread(target = run_thread ,args = (8,)) t1.start() t2.start() t1.join() t2.join() print(balance)
共享變量balance初始化為0 ,先加后減理論上最后的數值應該是0 ,但是經過t1,t2多次運行后balance的結果就不一定是0
代碼正常運行就像下邊:
t1: x1 = balance + 5 # x1 = 0 + 5 = 5 t1: balance = x1 # balance = 5 t1: x1 = balance - 5 # x1 = 5 - 5 = 0 t1: balance = x1 # balance = 0 t2: x2 = balance + 8 # x2 = 0 + 8 = 8 t2: balance = x2 # balance = 8 t2: x2 = balance - 8 # x2 = 8 - 8 = 0 t2: balance = x2
# balance = 0
結果 balance = 0
那是因為 balance = balance + n 是先將balance +n的值存進臨時變量,然后在將臨時變量存入balance
類似於
x = balance + n
balance = x
所以在多次加減賦值之后因為多線程的變量共享導致變量的數據改變
例如:
t1: x1 = balance + 5 # x1 = 0 + 5 = 5 t2: x2 = balance + 8 # x2 = 0 + 8 = 8 t2: balance = x2 # balance = 8 t1: balance = x1 # balance = 5 t1: x1 = balance - 5 # x1 = 5 - 5 = 0 t1: balance = x1 # balance = 0 t2: x2 = balance - 8 # x2 = 0 - 8 = -8 t2: balance = x2 # balance = -8 結果 balance = -8
所以要保證數據的正確要加鎖,保證在一個線程運算時,只能由一個線程去讀寫。
修改如下:
import time, threading lock = threading.Lock() balance = 0 def change_it(n): global balance balance = balance + n balance = balance - n def run_thread(n): for i in range(100000): lock.acquire() try: change_it(n) finally: lock.release() t1 = threading.Thread(target=run_thread, args=(5,)) t2 = threading.Thread(target=run_thread, args=(8,)) t1.start() t2.start() t1.join() t2.join() print(balance)
結果一直保持0
這樣保證變量在調用時不會被其他的線程讀寫