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