多進程與多線程
一張圖,先來回顧一下並行,並發,串行:

一、多核多線程
當我們要去買一台新電腦時,我們一般都會比較多台電腦的配置,而其中一項關鍵配置就是幾核幾線程。一般現在很多電腦都是4核8線程,甚至是8核16線程的。那么這里的4核8線程是什么意思呢?和cpu是什么關系呢?
1. 查看電腦核心數
開始菜單-->運行-->cmd-->輸入wmic-->輸入cpu get* 並將底部滾動條拖拽到如下圖所示位置


NumberOfCores:2(核數為2)
NumberOfLogicalProcessors:4(邏輯線程數為4)
即這就是所謂的2核4線程
2. cpu的超線程技術
以上我們可以看到我的電腦是2核4線程的,但我的電腦只有一個處理器(cpu)芯片,即2個核是指在一個cpu中集成了兩個完整的計算引擎(內核)。
多核
僅僅提高單核芯片的速度會遇到很多問題,英特爾工程師轉而“橫向發展”,提高計算機性能。線程應用能夠充分利用多個內核,在同樣的時間內完成更多的任務,大大提高cpu的性能。多核處理器是單枚芯片,可以插入一個處理器卡槽內,操作系統會利用相關資源將單枚芯片中的多個執行內核分立為多個處理器。
多線程(不同於程序中的多線程)
事實上單個執行內核的性能並沒有被充分利用,因此工程師們又采用了另一個思路去提高cpu性能,即讓單個執行內核可以同時執行多重線程,從而進一步提高cpu性能,這就是所謂的超線程技術。
雖然單線程核心每秒能處理成千上萬條指令,但任一時刻,內核只能對一條線程進行操作,而其實這個內核還有很多性能沒有被利用到,空閑着。超線程技術就是在一個執行內核上同時執行兩個線程,兩個線程共享這一個內核的資源。理論上來說就像兩個獨立的執行內核分別同時執行兩個線程一樣,但其實並不是這樣。當兩個線程同時需要同一個內核資源時,其中一個線程必須等待另一個線程使用完后釋放資源,才能繼續執行。所以超線程性能並不等於兩個執行內核的性能。這里的多線程只是邏輯上的多線程,並不是真正意義上獨立的多線程。
二、多進程與多線程
1. 多任務
思考這樣一個場景,你正在使用電腦一邊播放音樂,一邊瀏覽網頁,同時還在聊QQ。此時電腦上至少有三個任務在“同時”運行,其實還有許多任務在后台執行只是你看不到罷了。任務數遠大於cpu核心數,所以這里的多任務同時運行往往指的是並發執行,而不是並行執行。大量任務在cpu的多個內核上交替切換執行,但由於cpu執行速度太快,以至於我們感覺不到任務的切換,讓人感覺所有任務都是在同時運行着。事實上,如果cpu是2核2進程的,則同一時刻只能有2個任務同時執行;如果cpu是2核4進程的,理論上同一時刻能夠同時執行4個任務,實際上往往並不會達到4個任務並行執行,原因上節已經講述在此不再贅述。
2. 多進程與多線程
對於操作系統來說,一個任務就是一個進程。比如打開一個world就是一個進程,打開兩個world就是兩個進程,打開瀏覽器也是一個進程。但有些進程不單單只完成一件事,比如在瀏覽器上看電影時,瀏覽器既要播放視頻又要播放音頻還要播放字幕等,這樣在一個進程內就要做多件事,這多個子任務實際上就是進程中的線程。
由於每個進程至少要干一件事,多以每個進程至少有一個線程。多個線程的執行方式和多進程執行方式一樣,是由操作系統在多個線程間切換執行的,切換速度極快導致我們感覺多個線程是同時執行的,事實上,現代操作系統都將線程作為最小的調度單位,而將進程作為資源分配的最小單位。一個進程內的多個線程是可以並行運行在多個核上的,但這也並不是一定的,比如python的線程模型並不支持並行運行在多個核上。
3. 多任務與多進程,多線程的關系
結合以上兩節我們可以總結出同時執行多個任務的3種解決方案:
- 多進程模式:開啟多個進程,每個進程開啟一個線程,每個線程完成一件事,多個進程就完成多件事
- 多線程模式:開啟一個進程,一個進程里開啟多個線程,每個線程完成一件事,1個進程就完成多件事
- 多進程和多線程組合模式:開啟多個進程,每個進程內開啟多個線程,每個線程完成一件事,多個進程就完成多件事
以上三個解決方案中,方案三實現起來很復雜,需要解決的問題很多,使用的較少。而方案二,看似很好,一個進程就能完成多件事,那我們是不是可以將多個任務都在一個進程內的多個線程上完成呢?事實上,一個進程內不能無限制地開啟很多個線程,當線程數量超過一定上限時,進程內線程間的切換,上下文環境的保存恢復需要占用大量時間,導致cpu性能下降。
4. 多進程與多線程的關系及優缺點
進程與線程間的關系:
- 一個進程至少有一個線程,可以有多個線程,但不可有過多的線程,否則性能下降
- 一個進程內的多個線程可以並行運行在多核多線程的處理器上
- 一個線程只屬於一個進程,不可能兩個或多個進程擁有同一個線程
- 進程是操作系統資源分配的最小單位,一個進程內的多個線程共享該進程的資源
- 線程是操作系統調度的最小單位,即cpu分配給線程,真正在cpu上執行的是線程
多進程的優缺點
優點:每個進程間是相互獨立的,一個進程的崩潰不會影響到其他進程的執行,穩定性高。
缺點:進程創建,調度等開銷大。
多線程優缺點
優點:多線程直接共享進程資源,創建調度等開銷小。
缺點:正是由於多線程共享進程資源導致任何一個線程掛掉都可能導致整個進程奔潰。
不管是多進程還是多線程,如果數量一多,效率就會下降,因為系統調度會占用大量cpu時間。
三、python中的多線程
前面說到一個進程內的多個線程可以並行運行在多個cpu內核上,但Python程序的線程不能運行在多個內核中,所有線程都只能在一個cpu內核中交替執行。因為Python的線程雖然是真正的線程,但解釋器執行代碼時,有一個GIL(Global interpreter Lock)鎖,python線程在執行前必須先獲得GIL鎖,而一個進程中只有唯一的一個GIL鎖,導致python線程不能實現並行。即使是100個線程在100個核的cpu上執行,真正能用到的也只有一個核。python中雖然可以使用多線程,但無法利用多核的性能。
解決方案:
- 重寫python的解釋器,實現一個不帶GIL鎖的解釋器
- 對線程並行要求較高的程序,核心代碼使用C,C++或java來編寫
- 使用多進程來替代多線程,充分利用多核的性能。多個python進程各自有自己的GIL鎖,互不影響。
四、IO密集型 vs 計算密集型
是否需要開啟多進程,多線程?開啟多少個進程,線程?這與任務的類型有關。我們可以將任務分成IO密集型和計算密集型兩種。
IO密集型任務:IO密集型任務是指任務中更多的是等待IO請求,比如磁盤IO或網絡IO,這類任務的特點是cpu消耗的少,任務的大部分時間是在等待IO,因為IO的速度遠低於cpu的速度。這類任務,應開啟的更多數量的進程,線程,cpu的運行效率越高。一個任務阻塞時可以切換到其他就緒任務,提高cpu利用率。常見的大部分任務都是IO密集型任務,比如web應用。
計算密集型:這類任務主要為復雜的邏輯判斷和復雜的運算,需要進行大量的計算,消耗大量cpu資源。這類任務不能開啟太多,否則任務切換時會占用太多cpu時間,降低cpu性能。這類任務的執行要達到cpu的最高效率,任務數不能大於cpu的核心數,這樣不會將cpu時間浪費在切換任務上,而將所有時間用在計算上。
