一 引子
在Cpython解釋器中,同一個進程下開啟的多線程,同一時刻只能有一個線程執行,無法利用多核優勢首先:需要明確的一點是GIL并不是Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。就好比c++是一套語言(語法)標準,但是可以用不同的編譯器來編譯成可執行代碼,
例如:GCC,INTEL C++,Visual C++等。Python也一樣,同樣一段代碼可以通過CPython,PyPy,Psyco等不同的Python執行環境來執行。像其中的JPython就沒有GIL。然而因為CPython是
大部分環境下默認的Python執行環境。所以很多人的概念里CPython就是Python,也就想當然的把GIL歸結為Python語音的缺陷。所以這里要先明確一點:GIL并不是Python的特性,Python完全可
以不依賴與GIL
二 GIL介紹
GIL本質就是一把互斥鎖,既然是互斥鎖,所有互斥鎖的本質都一樣,都是將并發運行變成串行,以此來控制同一時間內共享數據只能被一個任務所修改,進而保證數據安全。
可以肯定一點是:保護不同的數據的安全,就應該加不同的鎖
要想了解GIL,首先確定一段,每次執行Python程序,就會產生一個獨立的進程。例如Python test.py,python aaa.py,python bb.py 會產生3個不同的Python進程
驗證Python test.py只會產生一個進程
1 2 3 4 |
|
1 2 3 4 5 6 7 8 |
|
在一個Python的進程內,不僅有test.py的主線程或者由該主線程開啟的其它線程,還有解釋器開啟的垃圾回收等解釋器級別的線程,總之,所有線程都運行在一個進程內
1 2 3 4 |
|
綜上:
如果多個線程的target=work,那么執行流程是:
多個線程先訪問到解釋器的代碼,即拿到執行權限,然后將target的代碼交給解釋器的代碼去執行
解釋器的代碼是所有線程共享,所以垃圾回收線程也可能訪問到解釋器的代碼而去執行,這就導致了一個問題:對于同一個數據100,可能線程1執行x=100的同時,而垃圾回收執行的是回收100的操作,解決這種問題沒有聲明高明的方法,就是加鎖處理,如下圖的GIL,保證Python解釋器同一時間只能執行一個任務的代碼
三 GIL與Lock?
問題:Python已經有一個GIL來保證同一時間只能有一個線程來執行了,為什么這里還需要lock?
首先:我們需要達成共識:鎖的目的是為了保護共享的數據,同一時間只能有一個線程來修改共享的數據
然后:我們可以得出結論:保護不同的數據就應該加不同的鎖
最后:問題是很明朗了,GIL與LOCK是兩把鎖,保護的數據不一樣,前者是解釋器級別的(當然保護的就是解釋器級別的數據,比如垃圾回收的數據),后者是保護用戶自己開發的應用程序的數據,很明顯GIL
負責這件事,只能用戶自定義加鎖處理,即Lock,如下圖:
分析:
1 2 3 4 5 6 7 |
|
示例代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
四 GIL與多線程
有了GIL的存在,同一時刻同一進程中只有一個線程被執行
問題:進程可以利用多核,但是開銷大,而Python的多線程開銷小,但卻無法利用多核優勢,也就是說Python沒用了,PHP才是最牛B的語言?
要解決這個問題,我們需要在幾個點上達成一致:
1 2 3 4 5 |
|
一個工人相當于CPU,此時計算相當于工人在干活,I/O阻塞相當于為工人干活提供所需原材料的過程,工人干活的過程中如果沒有原材料了,則工人干活的過程需要停止,直到原材料的到來
如果你的工廠的大多數任務需要有準備原材料的過程(I/O密集型),那么你有再多的工人,意義也不大,還不如一個人,在等材料的過程中讓工人去干別的活
反過來講,如果你的工廠原材料都齊全,那當然是工人越多,效率越高
結論:
1 2 3 |
|
假設我們有四個任務需要處理,處理方式肯定是要玩出并發的效果,解決方案可以是:
1 2 3 |
|
單核情況下,分析結果:
1 2 |
|
多核情況下,分析結果:
1 2 |
|
結論:
現在計算機基本上都是多核,Python對于計算密集型的任務開多個線程的效率并不能帶來多大性能上的提升,甚者不如串行(沒有大量切換),但是,對于I/O密集型的任務效率還是有顯著提升的
五? 多線程性能測試
如果并發的多個任務是計算 密集型:多進程效率高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
如果并發的多個任務是I/O密集型:多線程效率高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
應用
1 2 |
|