什么是全局解釋器鎖GIL
Python代碼的執(zhí)行由Python 虛擬機(jī)(也叫解釋器主循環(huán),CPython版本)來控制憾儒,Python 在設(shè)計(jì)之初就考慮到要在解釋器的主循環(huán)中蝶溶,同時(shí)只有一個(gè)線程在執(zhí)行膝蜈,即在任意時(shí)刻乙漓,只有一個(gè)線程在解釋器中運(yùn)行。對Python 虛擬機(jī)的訪問由全局解釋器鎖(GIL)來控制互婿,正是這個(gè)鎖能保證同一時(shí)刻只有一個(gè)線程在運(yùn)行捣郊。
在多線程環(huán)境中,Python 虛擬機(jī)按以下方式執(zhí)行:
1. 設(shè)置GIL
2. 切換到一個(gè)線程去運(yùn)行
3. 運(yùn)行:
????a. 指定數(shù)量的字節(jié)碼指令
????b. 線程主動讓出控制(可以調(diào)用time.sleep(0))
4. 把線程設(shè)置為睡眠狀態(tài)
5. 解鎖GIL
6. 再次重復(fù)以上所有步驟
在調(diào)用外部代碼(如C/C++擴(kuò)展函數(shù))的時(shí)候慈参,GIL 將會被鎖定呛牲,直到這個(gè)函數(shù)結(jié)束為止(由于在這期間沒有Python 的字節(jié)碼被運(yùn)行,所以不會做線程切換)驮配。
GIL的設(shè)計(jì)簡化了CPython的實(shí)現(xiàn)娘扩,使得對象模型,包括關(guān)鍵的內(nèi)建類型如字典壮锻,都是隱含可以并發(fā)訪問的琐旁。鎖住全局解釋器使得比較容易的實(shí)現(xiàn)對多線程的支持,但也損失了多處理器主機(jī)的并行計(jì)算能力猜绣。
但是灰殴,不論標(biāo)準(zhǔn)的,還是第三方的擴(kuò)展模塊掰邢,都被設(shè)計(jì)成在進(jìn)行密集計(jì)算任務(wù)是牺陶,釋放GIL。
還有辣之,就是在做I/O操作時(shí)掰伸,GIL總是會被釋放。對所有面向I/O 的(會調(diào)用內(nèi)建的操作系統(tǒng)C 代碼的)程序來說怀估,GIL 會在這個(gè)I/O 調(diào)用之前被釋放狮鸭,以允許其它的線程在這個(gè)線程等待I/O 的時(shí)候運(yùn)行。如果是純計(jì)算的程序奏夫,沒有 I/O 操作怕篷,解釋器會每隔 100 次操作就釋放這把鎖历筝,讓別的線程有機(jī)會執(zhí)行(這個(gè)次數(shù)可以通過 sys.setcheckinterval 來調(diào)整)如果某線程并未使用很多I/O 操作酗昼,它會在自己的時(shí)間片內(nèi)一直占用處理器(和GIL)。也就是說梳猪,I/O 密集型的Python 程序比計(jì)算密集型的程序更能充分利用多線程環(huán)境的好處麻削。