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

上面這張圖,就是 GIL 在 Python 程序的工作示例。其中,Thread 1、2、3 輪流執(zhí)行,每一個線程在開始執(zhí)行時,都會鎖住 GIL,以阻止別的線程執(zhí)行;同樣的,每一個線程執(zhí)行完一段后,會釋放 GIL,以允許別的線程開始利用資源。
如果線程一直阻塞呢?是不是就一直鎖住了?或者說線程是否就會完全執(zhí)行完了?
答案是NO。
CPython 中還有另一個機制,叫做間隔式檢查(check_interval),意思是 CPython 解釋器會去輪詢檢查線程 GIL 的鎖住情況,每隔一段時間,Python 解釋器就會強制當前線程去釋放 GIL,這樣別的線程才能有執(zhí)行的機會,這就是cpython為線程提供了并發(fā)能力。
但這個并發(fā)能力并不一定是我們想要的,因為我們的python代碼可能需要保證原子性,如:給10000長度的列表sort,如果因為cpython的間隔式檢查,在這個功能還沒執(zhí)行完的時候就將執(zhí)行權切換給了另外一個線程,這顯然不是我們想要的,顯然就很不線程安全了,所以我們需要人為加鎖
什么是線程安全?
因為同一進程內(nèi)的線程之間是資源共享的
- 共享的好處是,可以不用頻繁的加載資源,而資源加載是屬于IO操作,是比較耗時的
- 共享的壞處是,多線程間可以隨意修改資源,勢必會因為數(shù)據(jù)混亂而導致業(yè)務出錯
為了要保證多線程之間的資源一致性,所以Cpython解釋器使用了GIL,來保證每次只有一個線程能執(zhí)行,從一定程度上保證了線程安全。但并不絕對,在實際編碼過程中,依然要人為加鎖。
assert斷言
assert 表達式
表達式為False,拋出異常
用于單元測試
閉包
內(nèi)部函數(shù)對外部函數(shù)作用域里變量的引用。
函數(shù)內(nèi)的變量,只能在函數(shù)運行的時候才能使用,而一旦離開該作用域,就無法取到。而閉包,使得即使外部函數(shù)執(zhí)行完了,執(zhí)行內(nèi)部函數(shù)的時候依然可以調(diào)用外部函數(shù)的變量。因為內(nèi)部函數(shù)保存了外部函數(shù)作用域里的變量(是真的保存了,而不是copy了值)。
類似于 面向?qū)ο?,類似于在python文件里的函數(shù)引用了全局變量

裝飾器
裝飾器是用閉包實現(xiàn)的,那為啥裝飾器要用兩層函數(shù)實現(xiàn),而不能用一層函數(shù)實現(xiàn),如
def generator(func):
print("lalala")
return func
- 裝飾器的作用,是在函數(shù)前后做一些額外的操作,而如果只用一層函數(shù),無法在return func之后做額外的操作了
- 如果待裝飾函數(shù)有參數(shù),像這種單層裝飾器就無法傳遞內(nèi)部參數(shù)
- 其實裝飾器只是一個使用閉包思想的場景,其并沒有要求一層兩層還是三層,要看具體場景
協(xié)程
WHAT
并不是計算機系統(tǒng)提供(進程,線程),而是程序員人為創(chuàng)造的。
用戶態(tài)內(nèi)的上下文切換技術。
簡而言之,就是通過一個線程實現(xiàn)代碼之間的相互切換
WHY
在一個線程中,如果遇到IO等待,利用該空閑時間,再去干點其他的事。