深刻理解-CPU核心數與線程池併發線程數關係

那是一個風和日麗的下午!java

面試官微微一笑,對我說:「小夥子,合理配置線程池你是如何考慮的?面試

我微微一笑,說出了個人答案:算法

首先確認業務是CPU密集型仍是IO密集型的,數據庫

若是是CPU密集型的,那麼就應該儘可能少的線程數量,通常爲CPU的核數+1;編程

若是是IO密集型:因此可多分配一點 cpu核數*2 也可使用公式:CPU 核數 / (1 - 阻塞係數);其中阻塞係數在 0.8 ~ 0.9 之間。服務器

面試官心想,有點東西,接着追問:「那你是如何獲得的這個公式,或者說你是如何根據CPU核心數肯定線程池併發線程數的網絡

我心想這不是小瞧我嘛?不屑回答的我脫下了個人帽子併發

哈哈哈哈,進入正題!測試


1,追書溯源

關於如何計算併發的線程數量,通常分兩派,來自兩本書,且都是好書,線程

第一派:《Java Concurrency in Practice》即《java併發編程實踐》,咱們簡稱A派。

第二派:《Programming Concurrency on the JVM Mastering》即《Java 虛擬機併發編程》,咱們簡稱B派。

到底哪一個是對的?咱們截取書中部份內容具體看看。

A派一書中是這樣寫的

B派一書中是這樣寫的

2,大膽分析

對於A派,假設CPU跑滿,即撇開CPU使用率這個因素,A派認爲 線程數 = Ncpu * ( 1 + w/c )

大膽假設將B派的公式等於A派公式,

Ncpu / (1-阻塞係數) = Ncpu * ( 1 + w/c )阻塞係數 = 阻塞時間 /(阻塞時間+計算時間)

這個結論在派系二後續中獲得應徵,以下圖:

\color{red}{因此得出一個結論:A派和B派實際上是一個公式!}

3,實際運用

那麼實際使用中併發線程數如何設置呢?分析以下(咱們以A派公式爲例):

Nthreads = Ncpu * (1+w/c)

IO密集型:通常狀況下,若是存在IO,那麼確定w/c>1(阻塞耗時通常都是計算耗時的不少倍),可是須要考慮系統內存有限(每開啓一個線程都須要內存空間),這裏須要上服務器測試具體多少個線程數適合(CPU佔比、線程數、總耗時、內存消耗)。

若是不想去測試,保守點取1即,Nthreads=Ncpu*(1+1)=2Ncpu。這樣設置通常都OK。

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

再次概括下:

IO密集型 = 2Ncpu(能夠測試後本身控制大小,2Ncpu通常沒問題)(常出現於線程中:數據庫數據交互、文件上傳下載、網絡數據傳輸等等)

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

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

4,繼續研究

A派的另外一個說法

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

即,計算密集型=Ncpu+1,可是這種作法致使的多一個cpu上下文切換是否值得,這裏不考慮。讀者可本身考量。


本文借鑑概括:Flag Counter 《根據CPU核心數肯定線程池併發線程數》

相關文章
相關標籤/搜索