關於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 ...