多線程應用那個開多少線程合適


為什么要找最佳線程數

1.過多的線程只會造成,更多的內存開銷,更多的CPU開銷,但是對提升QPS確毫無幫助

2.使用多線程就是在正確的場景下通過設置正確個數的線程來充分的利用 CPU 和 I/O 最大化程序的運行速度。

從兩個方面和分析:

  • CPU 密集型程序
  • I/O 密集型程序

1、CPU 密集型程序

  一個完整請求,I/O操作可以在很短時間內完成, CPU還有很多運算要處理,也就是說 CPU 計算的比例占很大一部分,線程等待時間接近0

(1) 單核 CPU,所有線程都在等待 CPU 時間片。按照理想情況來看,四個線程執行的時間總和與一個線程5獨自完成是相等的,實際上我們還忽略了四個線程上下文切換的開銷。如圖

 

 

 

 

所以,單核CPU處理CPU密集型程序,這種情況並不太適合使用多線程。

(2) 多核cpu,比如四核四線程,每個線程都有 CPU 來運行,並不會發生等待 CPU 時間片的情況,也沒有線程切換的開銷。理論情況來看效率提升了 4 倍:

 

 

如果是多核CPU 處理 CPU 密集型程序,我們完全可以最大化的利用 CPU 核心數,應用並發編程來提高效率。

CPU 密集型程序的最佳線程數就是:

 

    因此對於 CPU 密集型來說,理論上 線程數量 = CPU 核數(邏輯),但是實際上,數量一般會設置為 CPU 核數(邏輯)+ 1(經驗值)。
計算(CPU)密集型的線程恰好在某時因為發生一個頁錯誤或者因其他原因而暫停,剛好有一個“額外”的線程,可以確保在這種情況下CPU周期不會中斷工作。

2、I/O密集型程序

  與 CPU 密集型程序相對,一個完整請求,CPU運算操作完成之后還有很多 I/O 操作要做,也就是說 I/O 操作占比很大部分,等待時間較長

在進行 I/O 操作時,CPU是空閑狀態,所以我們要最大化的利用 CPU,不能讓其是空閑狀態

單核 CPU 的情況下:

 

從上圖中可以看出,每個線程都執行了相同長度的 CPU 耗時和 I/O 耗時,如果你將上面的圖多畫幾個周期,CPU操作耗時固定,將 I/O 操作耗時變為 CPU 耗時的 3 倍,你會發現,CPU又有空閑了,這時你就可以新建線程 4,來繼續最大化的利用 CPU。
綜上:線程等待時間所占比例越高,需要越多線程;線程CPU時間所占比例越高,需要越少線程。

I/O 密集型程序的最佳線程數就是:

最佳線程數 = CPU核心數 * (1/CPU利用率) = CPU核心數 * (1 + (I/O耗時/CPU耗時))

舉例:

  如果cpu耗時:1,I/O耗時:9,那么cpu利用率10%,所以純理論你就可以說是 10N(N=CPU核數,當然也有說 10N + 1的,1應該是backup。

  如果幾乎全是 I/O耗時,那么CPU耗時就無限趨近於0,所以純理論你就可以說是 2N(N=CPU核數),當然也有說 2N + 1的,1應該是backup。

總結

1、多線程不一定就比單線程高效,比如大名鼎鼎的 Redis ,因為它是基於內存操作,這種情況下,單線程可以很高效的利用CPU。而多線程的使用場景一般時存在相當比例的I/O或網絡操作

2、從定性到定量的分析的過程,在開始沒有任何數據之前,我們可以使用上文提到的經驗值作為一個偽標准,其次就是結合實際來逐步的調優(綜合 CPU,內存,硬盤讀寫速度,網絡狀況等)

3、盲目的增加 CPU 核數也不一定能解決我們的問題,這就要求我們嚴格的編寫並發程序代碼

拓展

1、我們已經知道創建多少個線程合適了,為什么還要搞一個線程池出來?

  • 不受控風險
  • 頻繁創建開銷大

  不受控風險

  系統資源有限,每個人針對不同業務都可以手動創建線程,並且創建標准不一樣(比如線程沒有名字)。當系統運行起來,所有線程都在瘋狂搶占資源,內存被無情榨干耗盡,這好比一個正木馬程序(出現問題,自然也就不可能輕易的發現和解決)。

  頻繁創建開銷大 

   內存分配,對象初始化,線程創建,線程狀態保存等均需要資源  

 

 




 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM