Python多進程和多線程是雞肋嘛?【轉】

GIL是什麼

Python的代碼執行由 Python虛擬機(也叫解釋器主循環,CPython版本)來控制,Python在設計之初就考慮到在解釋器的主循環中,同時只有一個線程在運行。即每一個CPU在任意時刻只有一個線程在解釋器中運行。對 Python虛擬機訪問的控制由全局解釋鎖GIL控制,正是這個鎖來控制同一時刻只有一個線程可以運行。——在單核CPU下的多線程其實都只是併發,不是並行 。python

併發與並行區別網絡

  • 併發:兩個或多個事件在同一時間間隔發生,或者說交替作不一樣事件的能力,或者說不一樣的代碼塊交替執行。
  • 並行:兩個或者多個事件在同一時刻發生,或者說同時作不一樣事件的能力,或者說不一樣的代碼塊同時執行。

 

併發和並行的意義多線程

併發和並行均可以處理「多任務」,兩者的主要區別在因而否是「同時進行」多個的任務。可是涉及到任務分解(有前後依賴耦合度高的任務沒法作到並行)、任務運行(可能要考慮互斥、鎖、共享等)、結果合併。併發


Python 下的多線程

在Python多線程下,每一個線程的執行方式,以下:函數

  1. 獲取GIL
  2. 切換到這個線程去執行
  3. 運行代碼,這裏有兩種機制:
  4. 指定數量的字節碼指令(100個)
  5. 固定時間15ms線程主動讓出控制
  6. 把線程設置爲睡眠狀態
  7. 釋放GIL
  8. 再次重複以上步驟

在Python2中,在解釋器解釋執行任何 Python 代碼時,都須要先得到這把鎖才行(同一時間只會有一個得到了 GIL 的線程在跑,其它的線程都處於等待狀態等着 GIL 的釋放),在遇到 I/O 操做時會釋放這把鎖。若是是純計算的程序,沒有 I/O 操做,解釋器會每隔 100 次操做就釋放這把鎖,讓別的線程有機會執行(這個次數能夠經過 sys.setcheckinterval 來調整)也正是這種設定,是的多線程的CPU密集型計算很是雞肋,下面會講到爲什麼如此。性能

而在python3中,GIL不使用ticks計數(100次,釋放GIL),改成使用計時器(執行時間達到15ms閾值後,當前線程釋放 GIL),使得執行計算的次數更多,釋放次數減小,這樣對CPU密集型程序更加友好,但依然沒有解決GIL致使的同一時間只能執行一個線程的問題,因此效率依然不盡如人意。測試


那麼是否是Python的多線程是雞肋嘛?

CPU密集型(各類循環處理、計數等等),在這種狀況下,ticks計數很快就會達到閾值,而後觸發GIL的釋放與再競爭(多個線程來回切換是須要消耗資源的),因此python下的多線程對 CPU密集型代碼並不友好,會觸發至關頻繁的線程切換。線程

IO密集型(文件處理、網絡爬蟲等),多線程可以有效提高效率(單線程下有IO操做會進行IO 等待,形成沒必要要的時間浪費,而開啓多線程能在線程A等待時,自動切換到線程B,能夠不浪費 CPU的資源,從而能提高程序執行效率,一個線程得到GIL發送消息,而後等待返回消息(阻塞),Python此時釋放GIL, 其餘線程獲得GIL發送消息,而後一樣等待返回消息(阻塞)......,這樣保證了IO傳輸過程時間的合理利用,減小了IO等待形成的資源浪費,提升IO傳輸效率)。因此python的多線程對IO密集型代碼比較友好。設計


有哪些結論?

I/O密集型使用多線程併發執行提升效率、計算密集型使用多進程(multiprocessing )並行執行提升效率。一般程序既包含IO操做又包含計算操做,那麼這種狀況下,在開始併發任務以前,能夠先進行測試,測試多線程、多進程哪一個效率高就是用哪一種方式。協程

請注意:多核多線程比單核多線程更差,多核多進程下,CPU1釋放GIL後,其餘CPU上的線程都會進行競爭,但GIL可能會立刻又被CPU1拿到,CPU2釋放GIL後……,致使其餘幾個CPU上被喚醒後的線程會醒着等待到切換時間後又進入待調度狀態,這樣會形成線程顛簸(thrashing),致使效率更低。

多線程下的CPU密集型計算也不是無藥可醫,能夠利用ctypes繞過GIL,ctypes可使py直接調用任意的C動態庫的導出函數。所要作的只是把關鍵部分用 C/C++ 寫成 Python 擴展。並且,ctypes會在調用C函數前釋放GIL。

同時,能夠了解下協程,又稱微線程。

協程最大的優點就是協程極高的執行效率。由於子程序切換不是線程切換,而是由程序自身控制,所以,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優點就越明顯。

第二大優點就是不須要多線程的鎖機制,由於只有一個線程,也不存在同時寫變量衝突,在協程中控制共享資源不加鎖,只須要判斷狀態就行了,因此執行效率比多線程高不少。

由於協程是一個線程執行,那怎麼利用多核CPU呢?最簡單的方法是多進程+協程,既充分利用多核,又充分發揮協程的高效率,可得到極高的性能。

 

轉自

Python多進程和多線程是雞肋嘛? https://www.toutiao.com/a6738231652184490247/

相關文章
相關標籤/搜索