python解釋器
我們一直說python是解釋性語(yǔ)言,不需要編譯,并不是說操作系統(tǒng)真的就能識(shí)別.py文件的代碼了,機(jī)器永遠(yuǎn)只能識(shí)別01010101,要想在機(jī)器上運(yùn)行,編譯的過程少不了,而python解釋器的工作,就是將python代碼轉(zhuǎn)換成機(jī)器能識(shí)別的010101二進(jìn)制指令。
python解釋器是一個(gè)程序,常見的有:
- CPython:C語(yǔ)言開發(fā),使用最廣,默認(rèn)的解釋器
- IPython:基于CPython之上的交互式解釋器
- PyPy:采用JIT技術(shù),對(duì)python代碼進(jìn)行動(dòng)態(tài)編譯,追求執(zhí)行速度
- Jython:運(yùn)行在Java平臺(tái)上的解釋器,可以直接編譯成Java字節(jié)碼執(zhí)行
- IronPython:同理Jython,運(yùn)行在 .Net 平臺(tái)上
GIL全局解釋器鎖
同進(jìn)程內(nèi)的多線程,一個(gè)線程運(yùn)行會(huì)霸占python解釋器,使其他線程無法運(yùn)行,所以python的多線程其實(shí)并不是同時(shí)進(jìn)行的。而多進(jìn)程是由系統(tǒng)分配資源,等于每個(gè)進(jìn)程都有一個(gè)python解釋器,所以多進(jìn)程可以同時(shí)進(jìn)行,但是資源開銷大。
GIL底層實(shí)現(xiàn)原理

上面這張圖,就是 GIL 在 Python 程序的工作示例。其中,Thread 1、2、3 輪流執(zhí)行,每一個(gè)線程在開始執(zhí)行時(shí),都會(huì)鎖住 GIL,以阻止別的線程執(zhí)行;同樣的,每一個(gè)線程執(zhí)行完一段后,會(huì)釋放 GIL,以允許別的線程開始利用資源。
如果線程一直阻塞呢?是不是就一直鎖住了?或者說線程是否就會(huì)完全執(zhí)行完了?
答案是NO。
CPython 中還有另一個(gè)機(jī)制,叫做間隔式檢查(check_interval),意思是 CPython 解釋器會(huì)去輪詢檢查線程 GIL 的鎖住情況,每隔一段時(shí)間,Python 解釋器就會(huì)強(qiáng)制當(dāng)前線程去釋放 GIL,這樣別的線程才能有執(zhí)行的機(jī)會(huì),這就是cpython為線程提供了并發(fā)能力。
但這個(gè)并發(fā)能力并不一定是我們想要的,因?yàn)槲覀兊膒ython代碼可能需要保證原子性,如:給10000長(zhǎng)度的列表sort,如果因?yàn)閏python的間隔式檢查,在這個(gè)功能還沒執(zhí)行完的時(shí)候就將執(zhí)行權(quán)切換給了另外一個(gè)線程,這顯然不是我們想要的,顯然就很不線程安全了,所以我們需要人為加鎖
什么是線程安全?
因?yàn)橥贿M(jìn)程內(nèi)的線程之間是資源共享的
- 共享的好處是,可以不用頻繁的加載資源,而資源加載是屬于IO操作,是比較耗時(shí)的
- 共享的壞處是,多進(jìn)程間可以隨意修改資源,勢(shì)必會(huì)因?yàn)閿?shù)據(jù)混亂而導(dǎo)致業(yè)務(wù)出錯(cuò)
為了要保證多線程之間的資源一致性,所以Cpython解釋器使用了GIL,來保證每次只有一個(gè)線程能執(zhí)行,從一定程度上保證了線程安全。但并不絕對(duì),在實(shí)際編碼過程中,依然要人為加鎖。