GIL全域性直譯器鎖 學習筆記

2021-10-01 02:20:27 字數 3114 閱讀 5127

gil的全稱是:global interpreter lock,意思就是全域性直譯器鎖,這個gil並不是python的特性,他是只在cpython直譯器裡引入的乙個概念,而在其他的語言編寫的直譯器裡就沒有這個gil例如:jython,pypy。

為解決執行緒之間資料的一致性和狀態同步,設計了gil全域性直譯器鎖。例如在多執行緒中共享全域性變數的時候會有執行緒對全域性變數進行的資源競爭,會對全域性變數的修改產生不是我們想要的結果。乙個廣為流傳的測試**:

import threading

global_num =

0def

test1()

:global global_num

for i in

range

(1000000):

global_num +=

1print

("test1"

, global_num)

deftest2()

:global global_num

for i in

range

(1000000):

global_num +=

1print

("test2"

, global_num)

t1 = threading.thread(target=test1)

t2 = threading.thread(target=test2)

t1.start(

)t2.start(

)————————————————

80294572

這段**裡,我們搞了兩個執行緒,每個執行緒執行乙個方法,test1 是累加100000次,test2是累減100000次,按照**上看,應該結果為0,但是實際執行起來,並不是0,而且每次都不一樣。為什麼會出現這樣的情況。

我們來分析一下實際的執行過程

1.thread1拿到全域性變數global_num

2.thread1申請到python直譯器的gil

3.直譯器呼叫系統原生執行緒

4.在cpu1上執行規定的時間

5.執行時間到了,要求釋放gil等下一次得到gil的時候,程式從這裡接著這一次開始執行

6.thread2拿到了全域性變數,此時thread1對全域性global_num的操作並未完成,所以thread拿到的和thread拿到的global_num其實是相同的,這樣也很好解釋為什麼結果不是0, 而是其他莫名的數

7.thread2申請到了gil鎖

8.呼叫原生的執行緒

9…執行時間到了,要求釋放gil等下一次得到gil的時候,程式從這裡接著這一次開始執行

10.執行緒1又申請到了gil鎖,重複之前的操作。

所以,因為有gil的存在,會因為一些因素造成釋放直譯器執行緒,從而使我們預想的結果與實際結果有偏差,這樣的因素大致有兩種

保證每次對全域性變數進行操作的時候,只有乙個執行緒能夠拿到這個全域性變數;看下面的**:

import threading

import time

global_num =

0lock = threading.lock(

)def

test1()

:global global_num

lock.acquire(

)for i in

range

(1000000):

global_num +=

1 lock.release(

)print

("test1"

, global_num)

deftest2()

:global global_num

lock.acquire(

)for i in

range

(1000000):

global_num -=

1 lock.release(

)print

("test2"

, global_num)

t1 = threading.thread(target=test1)

t2 = threading.thread(target=test2)

start_time = time.time(

)t1.start(

)t2.start(

)————————————————

80294572

這樣,我們在執行的時候就能得到我們想要的結果,0

在cpython直譯器中,當我們的python**有乙個執行緒開始訪問直譯器的時候,gil會把這個大鎖給鎖上,此時此刻其他的執行緒只能幹等著,無法對直譯器的資源進行訪問,這一點就跟我們的互斥鎖相似。而只是這個過程發生在我們的cpython中,同時也需要等這個執行緒分配的時間到了,這個執行緒把gil釋放掉,類似我們互斥鎖的lock.release()一樣,另外的執行緒才開始跑起來,說白了,這無疑也是乙個單執行緒。

全域性直譯器鎖gil是python直譯器層面的鎖,解決直譯器中多個執行緒競爭資源的問題

執行緒互斥鎖是**層面的鎖,解決python程式中多執行緒競爭資源的問題

gil 對程式中線程的影響,簡單來說就是「乙個執行緒執行 python ,而其他 n 個睡眠或者等待 i/o.」(即保證同一時刻只有乙個執行緒對共享資源進行訪問) python 執行緒也可以等待threading.lock或者執行緒模組中的其他同步物件;執行緒處於這種狀態也稱之為」睡眠「。

乙個執行緒無論何時開始睡眠或等待網路 i/o,其他執行緒總有機會獲取 gil 執行 python **。這是協同式多工處理。cpython 還有搶占式多工處理。

當一項任務啟動,而在較長的或不確定的時間內,沒有執行任何 python **的需要,乙個執行緒便會讓出gil,從而其他執行緒可以獲取 gil 而執行 python。這種禮貌行為稱為協同式多工處理,它允許併發;多個執行緒同時等待不同事件。在同樣的時間內它們可以做更多的工作。

首先,python檔案被編譯成乙個位元組碼的簡單二進位制格式。

其次,python直譯器的主迴路,乙個名叫 pyeval_evalframeex() 的函式,流暢地讀取位元組碼,逐個執行其中的指令。

當直譯器通過位元組碼時,它會定期放棄gil,而不需要經過正在執行**的執行緒允許,這樣其他執行緒便能執行。

GIL 全域性直譯器鎖

1 描述python中gil的概念,以及它對python多執行緒的影響?編寫乙個多執行緒抓取網頁的程式,並闡明多執行緒抓取程式是否可比單執行緒效能有提公升,並解釋原因。答 gil global interpreter lock,即全域性直譯器鎖 1 python語言和gil沒有半毛錢關係。僅僅是由於...

GIL全域性直譯器鎖

gil 啥?他是如何產生的?gil產生的背景 在cpython解釋內部執行多個執行緒的時候,每個執行緒都需要直譯器內部申請相應的全域性資源,由於c語言本身比較底層造成cpython在管理所有全域性資源的時候並不能應對所有執行緒同時的資源請求,因此為了防止資源競爭而發生錯誤,對所有執行緒申請全域性資源...

全域性直譯器鎖GIL

我們使用高併發,一次是建立1萬個執行緒去修改乙個數並列印結果看現象 from threading import thread import osdef func args global n n args print n,os.getpid n 100t list for i in range 100...