面試官:線程池裏面到底該設置多少個線程?

一、拋出問題

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

第一派:《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上下文切換是否值得,這裏不考慮。

四、總結

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章