Python的GIL是什么鬼
? ? ? ? ?學習編程的時候拓哺,我們少會涉及到多任務(wù)寺晌。可是在python中使用多任務(wù)經(jīng)常會提到一個GIL鎖户魏,那么GIL到底是做什么的驶臊?有什么好處么?
GIL是什么
? ? ? ?首先需要明確的一點是GIL并不是Python的特性善茎,它是在實現(xiàn)Python解析器(CPython)時所引入的一個概念悠菜。中文譯為全局解釋器鎖肥照。
為什么會有GIL
? ? ? ? 由于物理上得限制,各CPU廠商在核心頻率上的比賽已經(jīng)被多核所取代纵寝。為了更有效的利用多核處理器的性能,就出現(xiàn)了多線程的編程方式星立,而隨之帶來的就是線程間數(shù)據(jù)一致性和狀態(tài)同步的困難爽茴。即使在CPU內(nèi)部的Cache也不例外,為了有效解決多份緩存之間的數(shù)據(jù)同步時各廠商花費了不少心思室奏,也不可避免的帶來了一定的性能損失。
? ? ? ? Python當然也逃不開胧沫,為了利用多核,Python開始支持多線程绒怨。而解決多線程之間數(shù)據(jù)完整性和狀態(tài)同步的最簡單方法自然就是加鎖江场。?于是有了GIL這把超級大鎖窖逗,而當越來越多的代碼庫開發(fā)者接受了這種設(shè)定后,他們開始大量依賴這種特性(即默認python內(nèi)部對象是thread-safe的碎紊,無需在實現(xiàn)時考慮額外的內(nèi)存鎖和同步操作)。
? ? ? ? ?慢慢的這種實現(xiàn)方式被發(fā)現(xiàn)是蛋疼且低效的仗考。但當大家試圖去拆分和去除GIL的時候音同,發(fā)現(xiàn)大量庫代碼開發(fā)者已經(jīng)重度依賴GIL而非常難以去除了。有多難秃嗜?做個類比权均,像MySQL這樣的“小項目”為了把Buffer Pool Mutex這把大鎖拆分成各個小鎖也花了從5.5到5.6再到5.7多個大版為期近5年的時間,并且仍在繼續(xù)锅锨。MySQL這個背后有公司支持且有固定開發(fā)團隊的產(chǎn)品走的如此艱難叽赊,那又更何況Python這樣核心開發(fā)和代碼貢獻者高度社區(qū)化的團隊呢?
? ? ? ? ?所以簡單的說GIL的存在更多的是歷史原因必搞。如果推到重來必指,多線程的問題依然還是要面對,但是至少會比目前GIL這種方式會更優(yōu)雅恕洲。
GIL的影響
? ? ? 接下來塔橡,我們使用一個案例來看一下GIL對pyuthon的影響。
上面是我們不在開啟多線程情況下的運行時間霜第,接下來我們循環(huán)同樣的次數(shù)葛家,看一下運行多線程運行時間
? ? ? ? 按理說,我們使用多線程的形式泌类,其實是想讓我們的程序運行的效率更高癞谒,可是我們可以發(fā)現(xiàn),時間上相差不多,如果當我們的數(shù)據(jù)更大的時候還有可能會變得更慢扯俱,那么為什么呢书蚪?
當前GIL設(shè)計的缺陷
基于pcode數(shù)量的調(diào)度方式
? ? ? ? GIL作為Cpython中的全局解釋器鎖,主要作用就是保護線程的安全迅栅,然后在同一個線程當中殊校,都會先將自己鎖住,阻止其他線程的執(zhí)行读存。
? ? ? ?為了直觀的理解GIL對于多線程帶來的性能影響为流,這里直接借用的一張測試結(jié)果圖(見下圖)。圖中表示的是兩個線程在雙核CPU上得執(zhí)行情況让簿。兩個線程均為CPU密集型運算線程敬察。綠色部分表示該線程在運行,且在執(zhí)行有用的計算尔当,紅色部分為線程被調(diào)度喚醒莲祸,但是無法獲取GIL導致無法進行有效運算等待的時間。?
由圖可見椭迎,GIL的存在導致多線程無法很好的立即多核CPU的并發(fā)處理能力锐帜。
那么Python的IO密集型線程能否從多線程中受益呢?我們來看下面這張測試結(jié)果畜号。顏色代表的含義和上圖一致缴阎。白色部分表示IO線程處于等待÷危可見痹升,當IO線程收到數(shù)據(jù)包引起終端切換后,仍然由于一個CPU密集型線程的存在视卢,導致無法獲取GIL鎖,從而進行無盡的循環(huán)等待。?
簡單的總結(jié)下就是:Python的多線程在多核CPU上绳锅,只對于IO密集型計算產(chǎn)生正面效果酝掩;而當有至少有一個CPU密集型線程存在,那么多線程效率會由于GIL而大幅下降。
然而驯嘱,GIL不能保證線程絕對安全喳坠。
? ? ? ?剛才我們提到了,GIL為了提高線程的安全性剃幌,那么我們就不用自己給線程加鎖了晾浴,反正python也會直接給我們加鎖,讓我們更安全抖棘,然而我們看一個案例:
得到的結(jié)果是:
? ? ? ? 兩個線程分別加了100000次钉答,我們想得到的結(jié)果是200000杈抢,然后我們得到的卻遠遠小于這個值,就是因為惶楼,我們的全能局解釋器鎖不能保證我們的線程安全。
? ? ? ?是因為何陆,我們GIL不能容忍一個線程一直占用資源,他會輪流執(zhí)行python的其他線程贷盲,由于咱們的CPU執(zhí)行速度夠快從而達到了一種“偽多線程”的效果剥扣。
總結(jié)
? ? ? ? Python GIL不是他的特性,而是歷史遺留的產(chǎn)物佳魔,因為最開始的計算機多數(shù)都是單核cpu晦炊,python的這種機制是無可厚非的宁脊,但是隨即計算機硬件的發(fā)展贤姆,我們Python想要解除這種機制卻不是那么容易了,因為還有其他的框架或者第三放工具在使用這種機制坐漏,如果修改弄砍,那么則導致其他無法使用。
? ? ? ? 那么我們就對此沒有辦法了么音婶?當然不是,我們可以使用其他解釋器寸士,也可以使用其他封裝的工具類碴卧,比如說numpy模塊 ,他們就是c語言寫的數(shù)據(jù)分析的模塊婶博,我們可以無縫連接使用荧飞。