多執行緒問題

2021-09-01 16:01:28 字數 2823 閱讀 3260

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

多執行緒問題

問題描述 有4個執行緒和1個公共的字元陣列。執行緒1的功能就是向陣列輸出a,執行緒2的功能就是向字元輸出b,執行緒3的功能就是向陣列輸出c,執行緒4的功能就是向陣列輸出d。要求按順序向陣列賦值abcdabcdabcd,abcd的個數由執行緒函式1的引數指定。注 c語言選手可使用windows sdk...

多執行緒問題

程式 是由多個程序組成的。可以理解為靜態的 程序 可以理解為執行中的程式。執行緒 是組成程序的單元,乙個程序中有多個執行緒。我們經常把執行緒看做是程序中的某乙個任務。方式一 繼承乙個thread類 方式二 實現乙個runnable介面 兩種方式相比較,哪個能好點那?一般建議是實現runnable介面...

多執行緒問題

執行緒先達到corepoolsize,達到了去排隊 佇列滿了就去新建執行緒,達到了maxpoolsize 就執行拒絕策略了。所以大家在取queuesize的時候,就要取getthreadpoolexecutor getpoolsize getthreadpoolexecutor getqueue s...