在之前,我們講過了,Python 中多個線程之間是可以共享全局變量的數據的。
但是,多線程共享全局變量是會出問題的。
假設兩個線程 t1 和 t2 都要對全局變量 g_num (默認是0)進行加1運算,t1 和 t2 都各對 g_num 加10次,g_num 的最終的結果應該為20。
但是由於多線程是同時操作,有可能出現下面情況:
在 g_num=0 時,t1 取得 g_num=0。此時系統把 t1 調度為”sleeping”狀態,把t2轉換為”running”狀態,t2 也獲得 g_num=0。
然后 t2 對得到的值進行加1並賦給 g_num,使得 g_num=1 。
接着系統又把 t2 調度為”sleeping”,把 t1 轉為”running”。線程t1又把它之前得到的0加1后賦值給g_num。
這樣導致雖然 t1 和 t2 都對 g_num 加1,但結果仍然是 g_num=1。
先看例子:
import threading
import time
g_num = 0
def work1(num):
global g_num
for i in range(num):
g_num += 1
print("----in work1, g_num is %d---" % g_num)
def work2(num):
global g_num
for i in range(num):
g_num += 1
print("----in work2, g_num is %d---" % g_num)
print("---線程創建之前g_num is %d---" % g_num)
t1 = threading.Thread(target=work1, args=(100,))
t1.start()
t2 = threading.Thread(target=work2, args=(100,))
t2.start()
# 確保子線程都運行結束
while len(threading.enumerate()) != 1:
time.sleep(1)
print("2個線程對同一個全局變量操作之后的最終結果是:%s" % g_num)
運行結果:
---線程創建之前g_num is 0---
----in work1, g_num is 100---
----in work2, g_num is 200---
2個線程對同一個全局變量操作之后的最終結果是:200
乍一看,好像沒出什么問題。那是因為數據太小了,我們現在把數據變大。
import threading
import time
g_num = 0
def work1(num):
global g_num
for i in range(num):
g_num += 1
print("----in work1, g_num is %d---" % g_num)
def work2(num):
global g_num
for i in range(num):
g_num += 1
print("----in work2, g_num is %d---" % g_num)
print("---線程創建之前g_num is %d---" % g_num)
t1 = threading.Thread(target=work1, args=(1000000,))
t1.start()
t2 = threading.Thread(target=work2, args=(1000000,))
t2.start()
# 確保子線程都運行結束
while len(threading.enumerate()) != 1:
time.sleep(1)
print("2個線程對同一個全局變量操作之后的最終結果是:%s" % g_num)
運行結果:
---線程創建之前g_num is 0---
----in work2, g_num is 1048576---
----in work1, g_num is 1155200---
2個線程對同一個全局變量操作之后的最終結果是:1155200
數越大,出現問題的概率越大,而且數據的偏差也越大。
結論
如果多個線程同時對同一個全局變量操作,會出現資源競爭問題,從而數據結果會不正確。
那能不能解決這個問題呢?
我們后面會講同步和互斥鎖的問題的。
通過同步和互斥鎖,我們可以解決 Python 中多線程共享全局變量時發生錯誤的問題。