1. 程式人生 > >為什麽python的多線程不能利用多核CPU,但是咱們在寫代碼的時候,多線程的確是在並發,而且還比單線程快。

為什麽python的多線程不能利用多核CPU,但是咱們在寫代碼的時候,多線程的確是在並發,而且還比單線程快。

全局 睡眠 read 處理 sleep roc 需要 寫代碼 強制

python裏的多線程是單cpu意義上的多線程,它和多cpu上的多線程有著本質的區別。
單cpu多線程:並發
多cpu多線程:並行內部包含並發

首先強調背景:
1、GIL是什麽?
GIL的全稱是Global Interpreter Lock(全局解釋器鎖),來源是python設計之初的考慮,為了數據安全所做的決定。
2、每個CPU在同一時間只能執行一個線程(在單核CPU下的多線程其實都只是並發,不是並行,並發和並行從宏觀上來講都是同時處理多路請求的概念。但並發和並行又有區別,並行是指兩個或者多個事件在同一時刻發生;而並發是指兩個或多個事件在同一時間間隔內發生。)

在Python多線程下,每個線程的執行方式:
1、獲取GIL
2、執行代碼直到sleep或者是python虛擬機將其掛起。
3、釋放GIL

可見,某個線程想要執行,必須先拿到GIL,我們可以把GIL看作是“通行證”,並且在一個python進程中,GIL只有一個。拿不到通行證的線程,就不允許進入CPU執行。

...
Py_begin_allow_threads
sleep((int)secs);
Py_end_allow-threads
...
這段代碼是sleep的代碼,在執行sleep之前,通過一個宏來釋放GIL,然後在睡眠結束執行其他代碼前又獲取GIL。其他一下操作,比如IO,也會有類似的操作,這樣就使得對於IO密集型的程序,或者是使用C庫進行計算的程序,還是可以在很大程度上避開GIL來取得線程並行的效果的。但對於純python代碼的程序,GIL恐怕還是躲不過去的。
還有一個問題,就是GIL怎麽釋放,我們看到在python/C API中提供了宏來進行釋放,那麽對於普通的python語句呢?解釋器會在執行一百條python代碼後強制釋放GIL,這就使得其它線程得以執行
最後需要說明的,就是這個GIL的問題是解釋器相關的,而不是語言相關的。也就是說它只是對於python語言解釋器的一種實現,並不是語言本身的特性。事實上,GIL就是解釋器的一個非常粗粒度的鎖,我們完全可以采用更細粒度的鎖來增加並行性,而且Gindo就寫過一個patch來取消GIL,不過好像最後的結果是細粒度鎖導致了單線程程序的性能下降了兩倍,所以最後還是決定優先保證單線程程序的性能,繼續保留GIL。但是python的其他兩個分支,Jython和IronPython,卻都沒有GIL的問題,從而可以實現線程的並行。為什麽呢?這裏也不知道原因了。


python追求的是簡單和簡潔.在代碼中加入多線程往往都是一件簡單的事情.這違背了python裏面的蟬.提供了多線程不代表他就是常規理解的多線程.和ruby一樣,ruby也提供了多線程但是確實偽線程.


1. 準確的說,只有獲得了GIL的線程可以執行Python ByteCode,也就是說,Python ByteCode不能並行在多核上運行。但是Python裏有大量的C代碼,這些代碼可以不受GIL的限制。
2. 誰說並行一定要多線程?早在沒有線程那會兒Unix甚至Windows就並行的好好的了,連DOS下都有TSR。就算是純Python,你一樣可以用multiprocess做並行,一樣能把CPU跑滿。

為什麽python的多線程不能利用多核CPU,但是咱們在寫代碼的時候,多線程的確是在並發,而且還比單線程快。