
前言
上節(jié)課我們分享了Python多線程的基礎(chǔ)語法,以及GIL的相關(guān)概念,這節(jié)課我們重點(diǎn)講解一個(gè)知識點(diǎn),就是多線程的數(shù)據(jù)安全問題。
數(shù)據(jù)安全問題
我們首先來舉一個(gè)例子,這里定義兩個(gè)函數(shù),一個(gè)是自加1,一個(gè)時(shí)自減1,按正常的邏輯來說,最后這個(gè)值應(yīng)該是0,但是程序每次運(yùn)行的結(jié)果都不一樣,有正數(shù),也有負(fù)數(shù)。
import threading
num = 0
def add():
global num
for i in range(10000000):
num += 1
def sub():
global num
for i in range(10000000):
num -= 1
t1 = threading.Thread(target=add)
t2 = threading.Thread(target=sub)
t1.start()
t2.start()
t1.join()
t2.join()
print(num)
這就是多線程的數(shù)據(jù)安全的問題,我簡單解釋一下,因?yàn)榫€程會在兩個(gè)函數(shù)中來回切換,好比在add函數(shù)中,剛準(zhǔn)備加1時(shí),程序被打斷,跳到了sub函數(shù)中繼續(xù)執(zhí)行,這就會導(dǎo)致num值的改變。
我們舉一個(gè)現(xiàn)實(shí)中的案例,很多人搶一張火車票,如果是多線程,當(dāng)一個(gè)人在搶票時(shí),突然切換到另外一個(gè)人買票,他買到了,然后又返回到第一個(gè)人,他這邊還是顯示的還有一張票,但其實(shí)后臺已經(jīng)沒票了。
鎖
這時(shí)我們就可以手動(dòng)加鎖來解決這樣的問題。
import threading
num = 0
lock = threading.Lock()
def add():
lock.acquire()
global num
for i in range(10000000):
num += 1
lock.release()
def sub():
lock.acquire()
global num
for i in range(10000000):
num -= 1
lock.release()
t1 = threading.Thread(target=add)
t2 = threading.Thread(target=sub)
t1.start()
t2.start()
t1.join()
t2.join()
print(num)
acquire函數(shù)就是申請鎖,release就是釋放鎖,這樣就能保證數(shù)據(jù)的安全。
今天的分享就到這了,我們下期再見~