python GIL的解讀

前言

本篇文章主要是看完UnderstandingGIL.pdf后的一些理解

http://www.dabeaz.com/python/UnderstandingGIL.pdf

GIL什么是?

簡單翻譯一下:在CPython解釋器下,全局解釋器鎖GIL是為了保證python多線程安全的一把互斥鎖。這把鎖是必要的,主要因為CPython的內(nèi)存管理器不是線程安全的。(但是,自從GIL誕生后,所有其他功能都是基于GIL來實現(xiàn)了)

劃重點:

1、GIL是一把在Cpython解釋器下,針對多線程的全局互斥鎖。

? ? ? ? 解讀:Cpython解釋器下的GIL,也就是說有些python解釋器是不使用GIL的(但Cpython是主流)。

? ? ? ? ? ? ? ? ?? GIL是針對多線程的鎖,所以跟多進程,協(xié)程什么的就不搭邊啦。

2、這把鎖是必要的。

? ? ? ? 解讀:python的線程是真正的操作系統(tǒng)線程,python將線程的管理完全交由操作系統(tǒng)。(python認(rèn)為操作系統(tǒng)自身的線程管理已經(jīng)很好了,沒必要再搞一套出來。感覺就像我們平時用標(biāo)準(zhǔn)庫一樣)這種設(shè)計的合理性在于當(dāng)我們的CPU是單核時,GIL問題是不存在的,一個線程釋放GIL時,任何一個線程被喚醒(也包括自身)都能獲取到GIL,繼續(xù)工作,等下一次再釋放GIL時,依然是所有線程來獲取GIL,如下圖。但多核CPU時,現(xiàn)象是有所差別的,后面會繼續(xù)分析。

3、其他功能都是基于GIL來實現(xiàn)

? ? ? ? 解讀:這就解釋了為啥這么多年過去了,在多核CPU盛行的情況下,GIL這種明顯的性能瓶頸為什么依然去不掉,因為要改的實在太多了

GIL是如何工作的

關(guān)于python單核單進程,單核多進程,單核多線程,多核多進程,多核多線程的性能比較,本文就不再一一貼圖了。結(jié)論上來講,python的多核多線程要比單核單線程的性能還要差!

在了解GIL工作原理之前先提兩個不太熟悉的概念:

1、Tick,可以理解為程序執(zhí)行時的字節(jié)碼(可能理解有誤,沒有找到官方的說明,需要用到dis.dis方法將代碼轉(zhuǎn)換成匯編后才能識別出1個tick)。一個簡單的減法操作會用到4個tick。

2、OS Scheduing,操作系統(tǒng)在多任務(wù)操作時,會將待進行的任務(wù)寫入的一個隊列,并分配優(yōu)先級。

下面要分情況討論了(觸發(fā)GIL釋放有兩種情況:I/O觸發(fā)和ticks觸發(fā),這里不做劃分,只分析單核和多核):

1、單核CPU情況

當(dāng)線程1達到釋放GIL的條件時,向操作系統(tǒng)發(fā)送釋放GIL的信號(signal),操作系統(tǒng)拿到GIL后,把GIL分配給schedule隊列準(zhǔn)備好的線程2上,線程2拿到GIL后,進行上下文切換,開始工作。并且GIL有很大的幾率依然會回到線程1,這樣很好,減少了不必要的上下文切換。

2、多核CPU情況:

當(dāng)線程1達到釋放GIL的條件時,向操作系統(tǒng)發(fā)送釋放GIL的信號(signal),操作系統(tǒng)拿到GIL后,把GIL分配給schedule隊列,把此時和單核CPU出現(xiàn)差別。在多核下,可運行的線程們在每個CPU上都可以被喚醒,每個可以被喚醒的線程都認(rèn)為自己可以去爭搶這個GIL,但最終只有1個CPU上的線程能夠搶到這個GIL,而其他被喚醒的線程發(fā)現(xiàn)沒有GIL了,又接著回去干自己的工作,并且浪費了CPU的時間。感覺類似驚群效應(yīng),不知道這個理解是否合理


多核CPU多線程的解決方案

1、根據(jù)我們對定義的解讀,既然GIL是Cpython解釋器下的GIL,那么我們尋找一個不用GIL的python解釋器就好了。(雖然理論上沒毛病,但沒見過這么做的)

2、等。等python版本更新,然后用新版本的python。沒錯,我們什么都不用做,python社區(qū)的大神們比我們更想解決這個問題。目前來看,從python3.2之后,引入了TIMEOUT來替換ticks的計數(shù),這會使性能更好一些。

3、根據(jù)之前的分析,我們能夠確定單核CPU的時候,是不存在GIL問題的,而GIL又是針對某個進程下的多線程。由此可以提出一種解決方案:把進程綁定到固定的CPU上,然后在這個進程下使用多線程處理業(yè)務(wù)。這時候,雖然計算性能比較依賴單個CPU的主頻,但繞過了GIL,并發(fā)能力絕對是提高了。

介紹一個叫做affinity的包,將進程綁定到指定CPU用,之前寫過一段小例子可供參考(自己對這種方案產(chǎn)生了懷疑-_-!)https://github.com/dsgdtc/understanding_bindingcpu

4、雖然說了GIL這么多的壞話,但并不意味著完全舍棄多線程了。

5、用協(xié)程,python3.6+后asyncio的支持越來越好了

參考資料

http://www.dabeaz.com/python/UnderstandingGIL.pdf

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容