根據CPU核心數確定線程池並發線程數


一、拋出問題

關於如何計算並發線程數,一般分兩派,來自兩本書,且都是好書,到底哪個是對的?問題追蹤后,整理如下:

第一派:《Java Concurrency in Practice》即《java並發編程實踐》,如下圖:

 

如上圖,在《Java Concurrency in Practice》一書中,給出了估算線程池大小的公式:

Nthreads=Ncpu*Ucpu*(1+w/c),其中

Ncpu=CPU核心數

Ucpu=cpu使用率,0~1

W/C=等待時間與計算時間的比率

 

第二派:《Programming Concurrency on the JVM Mastering》即《Java 虛擬機並發編程》

線程數=Ncpu/(1-阻塞系數)

二、分析

對於派系一,假設cpu100%運轉,即撇開CPU使用率這個因素,線程數=Ncpu*(1+w/c)。

現在假設將派系二的公式等於派系一公式,即Ncpu/(1-阻塞系數)=Ncpu*(1+w/c),===》阻塞系數=w/(w+c),即阻塞系數=阻塞時間/(阻塞時間+計算時間),這個結論在派系二后續中得到應征,如下圖:

由此可見,派系一和派系二其實是一個公式......這樣我就放心了......

 

三、實際應用

那么實際使用中並發線程數如何設置呢?分析如下(我們以派系一公式為例):

Nthreads=Ncpu*(1+w/c)

IO密集型:一般情況下,如果存在IO,那么肯定w/c>1(阻塞耗時一般都是計算耗時的很多倍),但是需要考慮系統內存有限(每開啟一個線程都需要內存空間),這里需要上服務器測試具體多少個線程數適合(CPU占比、線程數、總耗時、內存消耗)。如果不想去測試,保守點取1即,Nthreads=Ncpu*(1+1)=2Ncpu。這樣設置一般都OK。

計算密集型:假設沒有等待w=0,則W/C=0. Nthreads=Ncpu。

至此結論就是:

IO密集型=2Ncpu(可以測試后自己控制大小,2Ncpu一般沒問題)(常出現於線程中:數據庫數據交互、文件上傳下載、網絡數據傳輸等等)

計算密集型=Ncpu(常出現於線程中:復雜算法)

java中:Ncpu=Runtime.getRuntime().availableProcessors()

=========================此處可略過=============================================

當然派系一種《Java Concurrency in Practice》還有一種說法,

即對於計算密集型的任務,在擁有N個處理器的系統上,當線程池的大小為N+1時,通常能實現最優的效率。(即使當計算密集型的線程偶爾由於缺失故障或者其他原因而暫停時,這個額外的線程也能確保CPU的時鍾周期不會被浪費。)

即,計算密集型=Ncpu+1,但是這種做法導致的多一個cpu上下文切換是否值得,這里不考慮。讀者可自己考量。

======================================================================

四、總結

選擇線程池並發線程數的因素很多:任務類型、內存等線程中使用到所有資源都需要考慮。本文經過對現有文獻的分析論證,得出結論,並給出了實際應用公式,實乃工程師之福利,技術之典范......

 


免責聲明!

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



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