多執行緒同步

2021-09-01 23:47:46 字數 2823 閱讀 7362

關於gil的示例問題,為什麼使用多執行緒之後,加了100w次和減了100w次之後,數值不是為0的

使用dis庫來檢視位元組碼

from dis import dis

def add1():

global a

a += 1

dis(add1)

輸出

19           0 load_global              0 (a)

2 load_const 1 (1)

4 inplace_add

6 store_global 0 (a)

8 load_const 0 (none)

10 return_value

表示給a加上1這個值

為什麼我們加上100w 減去100w會出現數字不對的問題,因為為什麼使用了多執行緒來計算,但是由於gil的存在,python同時只會有乙個執行緒在執行,這就涉及到了控制權的問題,gil會分配鎖給執行緒,有鎖的執行緒去執行位元組碼,但是gil的鎖分配是有策略的。比如遇到io操作時候回切換鎖,就像我們上面的sleep一樣,遇到了sleep程式直接向下執行,不會等待。其實就是gil做的操作。還有比如計算***次就會切換操作。比如我們的加減100w次就會在加的途中去切換鎖。就可能導致加的時候賦值變數沒有執行完,就切換到減法去了。然後數字被減掉了。等等問題導致最後結果不是0

問題解決:

我們可以使用鎖來解決上面的問題

把a+1的操作鎖住,讓他不能釋放,所以減法就不能去競爭加法時候的鎖

import threading

from dis import dis

a = 0

lock = threading.lock()

def add():

global a

global lock

for i in range(100000):

lock.acquire()

a += 1

lock.release()

def minus():

global a

global lock

for i in range(100000):

lock.acquire()

a -= 1

lock.release()

if __name__ == '__main__':

t1 = threading.thread(target=add)

t2 = threading.thread(target=minus)

t1.start()

t2.start()

t1.join()

t2.join()

print(a)

鎖有兩種狀態:鎖定和未鎖定。而且它也只支援兩個函式:獲得鎖和釋放鎖

當多執行緒爭奪鎖時,允許第乙個獲得鎖的執行緒進入臨界區,並執行**。所有之後到達 的執行緒將被阻塞,直到第乙個執行緒執行結束,退出臨界區,並釋放鎖。此時,其他等待的線 程可以獲得鎖並進入臨界區。不過請記住,那些被阻塞的執行緒是沒有順序的(即不是先到先 執行),勝出執行緒的選擇是不確定的,而且還會根據 python 實現的不同而有所區別。

所以說我們就可以在上面的示例**中加入鎖lock = lock(),然後使用lock.acquire()lock.release來釋放鎖

所以我們會說,如果加鎖會消耗資源,因為加鎖或者釋放鎖的過程中都會消耗資源

我們看這乙個例子

lock = threading.lock()

def minus():

global a

global lock

for i in range(100000):

lock.acquire()

a -= 1

lock.acquire()

lock.release()

lock.release()

if __name__ == '__main__':

t2 = threading.thread(target=minus)

t2.start()

t2.join()

print(a)

上面的例子程式永遠不會結束,因為我們人為的造成了死鎖,這是一種死鎖產生方式,當執行緒獲取到鎖的時候,鎖還沒有release,就又去申請鎖,這個時候,gil由於鎖只有釋放掉才會准許你去獲取鎖,所以獲取鎖的操作一直卡住,程式永遠不會結束。

rlock

上面的問題我們可以使用rlock來解決,一般在程式中我們也會使用rlock來書寫程式。因為lock會造成死鎖的情況。而rlock很簡單。只需要你去申明rlock並且accquire和realse的次數是一樣的,那麼程式就不會鎖住

**示例

lock = threading.rlock()

def minus():

global a

global lock

for i in range(100000):

lock.acquire()

a -= 1

lock.acquire()

lock.release()

lock.release()

if __name__ == '__main__':

t2 = threading.thread(target=minus)

t2.start()

t2.join()

print(a)

多執行緒同步

synchronized 物件 其中物件相當於乙個標誌 鎖 用於判斷 同步 塊 同步的前提必須是兩個或兩個以上的執行緒,且共用同乙個鎖 同步解決了多執行緒的安全問題 弊端 多執行緒需要判斷鎖,消耗了資源 同步函式 將synchronized放在函式名前面即可 即具有同步性質 使用的鎖是this 靜態...

多執行緒同步

同步 即限制某個資源在同一時間只能被同乙個執行緒訪問。執行緒安全問題 多個執行緒共同處理共享資源所導致的。解決 多執行緒處理乙個共享資源時,將處理共享資源的 利用關鍵字synchronized修飾。同步 塊 synchronized修飾 塊,synchronized lock 同步方法 synchr...

多執行緒同步

子執行緒迴圈10次,接著主線程迴圈100,接著又回到子執行緒迴圈10次,接著再回到主線程又迴圈100,如此迴圈50次,請寫出程式 package com.itcast public class traditionthreadcommuncation start 子執行緒 for int j 1 j ...