1.執行緒池和CPU核心數的關係
一般說來,大家認為執行緒池的大小經驗值應該這樣設定(其中N為CPU processors的個數)(1)如果是CPU密集型應用,則執行緒池大小設定為N+1(或者是N),執行緒的應用場景:主要是複雜演算法(2)如果是IO密集型應用,則執行緒池大小設定為2N+1(或者是2N),執行緒的應用場景:主要是:資料庫資料的互動,檔案上傳下載,網路資料傳輸等等+1的原因是:即使當計算密集型的執行緒偶爾由於缺失故障或者其他原因而暫停時,這個額外的執行緒也能確保CPU的時鐘週期不會被浪費。
1. CPU密集型(CPU-bound)
CPU密集型也叫計算密集型,指的是系統的硬碟、記憶體效能相對CPU要好很多,此時,系統運作大部分的狀況是CPU Loading 100%,CPU要讀/寫I/O(硬碟/記憶體),I/O在很短的時間就可以完成,而CPU還有許多運算要處理,CPU Loading很高。
在多重程式系統中,大部份時間用來做計算、邏輯判斷等CPU動作的程式稱之CPU bound。例如一個計算圓周率至小數點一千位以下的程式,在執行的過程當中絕大部份時間用在三角函式和開根號的計算,便是屬於CPU bound的程式。
CPU bound的程式一般而言CPU佔用率相當高。這可能是因為任務本身不太需要訪問I/O裝置,也可能是因為程式是多執行緒實現因此遮蔽掉了等待I/O的時間。
2. IO密集型(I/O bound)
IO密集型指的是系統的CPU效能相對硬碟、記憶體要好很多,此時,系統運作,大部分的狀況是CPU在等I/O (硬碟/記憶體) 的讀/寫操作,此時CPU Loading並不高。
I/O bound的程式一般在達到效能極限時,CPU佔用率仍然較低。這可能是因為任務本身需要大量I/O操作,而pipeline做得不是很好,沒有充分利用處理器能力。
一般說來,大家認為執行緒池的大小經驗值應該這樣設定:(其中N為CPU processors的個數)
(1)如果是CPU密集型應用,則執行緒池大小設定為N+1(或者是N),執行緒的應用場景:主要是複雜演算法
(2)如果是IO密集型應用,則執行緒池大小設定為2N+1(或者是2N),執行緒的應用場景:主要是:資料庫資料的互動,檔案上傳下載,網路資料傳輸等等
+1的原因是:即使當計算密集型的執行緒偶爾由於缺失故障或者其他原因而暫停時,這個額外的執行緒也能確保CPU的時鐘週期不會被浪費。
如果一臺伺服器上只部署這一個應用並且只有這一個執行緒池,那麼這種估算或許合理,具體還需自行測試驗證。
但是,IO最佳化中,這樣的估算公式可能更適合:
最佳執行緒數目 = ((執行緒等待時間+執行緒CPU時間)/執行緒CPU時間 )* CPU數目。
因為很顯然:
(1)執行緒等待時間所佔比例越高,需要越多執行緒。
(2)執行緒CPU時間所佔比例越高,需要越少執行緒。
eg:
比如平均每個執行緒CPU執行時間為0.5s,而執行緒等待時間(非CPU執行時間,比如IO)為1.5s,CPU核心數為8,
那麼根據上面這個公式估算得到:
((0.5+1.5)/0.5)8=32。
這個公式進一步轉化為:最佳執行緒數目 = (執行緒等待時間與執行緒CPU時間之比 + 1) CPU數目。
剛剛說到的執行緒池大小的經驗值,其實是這種公式的一種估算值。
((0.5+1.5)/0.5)*8=32。
這個公式進一步轉化為:最佳執行緒數目 = (執行緒等待時間與執行緒CPU時間之比 + 1)* CPU數目。
2.常見概念:CPU的核心數,CPU的執行緒數
CPU的核心數:
CPU的核心數是指物理上,也就是硬體上存在著幾個核心。
比如,雙核就是包括2個相對獨立的CPU核心單元組,四核就包含4個相對獨立的CPU核心單元組
CPU的執行緒數:
對於一個CPU,執行緒數總是大於或等於核心數的。
(1)一個核心最少對應一個執行緒,但透過超執行緒技術,一個核心可以對應兩個執行緒,也就是說它可以同時執行兩個執行緒。
(2)CPU之所以要增加執行緒數,是源於多工處理的需要。執行緒數越多,越有利於同時執行多個程式,因為執行緒數等同於在某個瞬間CPU能同時並行處理的任務數。
在Windows中,在cmd命令中輸入“wmic”,然後在出現的新視窗中輸入“cpu get *”即可檢視物理CPU數、CPU核心數、執行緒數。
其中:
Name:表示物理CPU數
NumberOfCores:表示CPU核心數
NumberOfLogicalProcessors:表示CPU執行緒數
(1)CPU的執行緒數概念僅僅只針對Intel的CPU才有用,因為它是透過Intel超執行緒技術來實現的
(2)如果沒有超執行緒技術,一個CPU核心對應一個執行緒。 所以,對於AMD的CPU來說,只有核心數的概念,沒有執行緒數的概念。
3.是否使用執行緒池就一定比使用單執行緒高效呢?
答案是否定的,比如Redis就是單執行緒的,但它卻非常高效,基本操作都能達到十萬量級/s。從執行緒這個角度來看,部分原因在於:
(1)多執行緒帶來執行緒上下文切換開銷,單執行緒就沒有這種開銷
(2)鎖,當然“Redis很快”更本質的原因在於:
Redis基本都是記憶體操作,這種情況下單執行緒可以很高效地利用CPU。而多執行緒適用場景一般是:存在相當比例的IO和網路操作。
所以即使有上面的簡單估算方法,也許看似合理,但實際上也未必合理,都需要結合系統真實情況(比如是IO密集型或者是CPU密集型或者是純記憶體操作)和硬體環境(CPU、記憶體、硬碟讀寫速度、網路狀況等)來不斷嘗試達到一個符合實際的合理估算值。
1.執行緒池和CPU核心數的關係
一般說來,大家認為執行緒池的大小經驗值應該這樣設定(其中N為CPU processors的個數)(1)如果是CPU密集型應用,則執行緒池大小設定為N+1(或者是N),執行緒的應用場景:主要是複雜演算法(2)如果是IO密集型應用,則執行緒池大小設定為2N+1(或者是2N),執行緒的應用場景:主要是:資料庫資料的互動,檔案上傳下載,網路資料傳輸等等+1的原因是:即使當計算密集型的執行緒偶爾由於缺失故障或者其他原因而暫停時,這個額外的執行緒也能確保CPU的時鐘週期不會被浪費。
1. CPU密集型(CPU-bound)
CPU密集型也叫計算密集型,指的是系統的硬碟、記憶體效能相對CPU要好很多,此時,系統運作大部分的狀況是CPU Loading 100%,CPU要讀/寫I/O(硬碟/記憶體),I/O在很短的時間就可以完成,而CPU還有許多運算要處理,CPU Loading很高。
在多重程式系統中,大部份時間用來做計算、邏輯判斷等CPU動作的程式稱之CPU bound。例如一個計算圓周率至小數點一千位以下的程式,在執行的過程當中絕大部份時間用在三角函式和開根號的計算,便是屬於CPU bound的程式。
CPU bound的程式一般而言CPU佔用率相當高。這可能是因為任務本身不太需要訪問I/O裝置,也可能是因為程式是多執行緒實現因此遮蔽掉了等待I/O的時間。
2. IO密集型(I/O bound)
IO密集型指的是系統的CPU效能相對硬碟、記憶體要好很多,此時,系統運作,大部分的狀況是CPU在等I/O (硬碟/記憶體) 的讀/寫操作,此時CPU Loading並不高。
I/O bound的程式一般在達到效能極限時,CPU佔用率仍然較低。這可能是因為任務本身需要大量I/O操作,而pipeline做得不是很好,沒有充分利用處理器能力。
一般說來,大家認為執行緒池的大小經驗值應該這樣設定:(其中N為CPU processors的個數)
(1)如果是CPU密集型應用,則執行緒池大小設定為N+1(或者是N),執行緒的應用場景:主要是複雜演算法
(2)如果是IO密集型應用,則執行緒池大小設定為2N+1(或者是2N),執行緒的應用場景:主要是:資料庫資料的互動,檔案上傳下載,網路資料傳輸等等
+1的原因是:即使當計算密集型的執行緒偶爾由於缺失故障或者其他原因而暫停時,這個額外的執行緒也能確保CPU的時鐘週期不會被浪費。
如果一臺伺服器上只部署這一個應用並且只有這一個執行緒池,那麼這種估算或許合理,具體還需自行測試驗證。
但是,IO最佳化中,這樣的估算公式可能更適合:
最佳執行緒數目 = ((執行緒等待時間+執行緒CPU時間)/執行緒CPU時間 )* CPU數目。
因為很顯然:
(1)執行緒等待時間所佔比例越高,需要越多執行緒。
(2)執行緒CPU時間所佔比例越高,需要越少執行緒。
eg:
比如平均每個執行緒CPU執行時間為0.5s,而執行緒等待時間(非CPU執行時間,比如IO)為1.5s,CPU核心數為8,
那麼根據上面這個公式估算得到:
((0.5+1.5)/0.5)8=32。
這個公式進一步轉化為:最佳執行緒數目 = (執行緒等待時間與執行緒CPU時間之比 + 1) CPU數目。
剛剛說到的執行緒池大小的經驗值,其實是這種公式的一種估算值。
比如平均每個執行緒CPU執行時間為0.5s,而執行緒等待時間(非CPU執行時間,比如IO)為1.5s,CPU核心數為8,
那麼根據上面這個公式估算得到:
((0.5+1.5)/0.5)*8=32。
這個公式進一步轉化為:最佳執行緒數目 = (執行緒等待時間與執行緒CPU時間之比 + 1)* CPU數目。
剛剛說到的執行緒池大小的經驗值,其實是這種公式的一種估算值。
2.常見概念:CPU的核心數,CPU的執行緒數
CPU的核心數:
CPU的核心數是指物理上,也就是硬體上存在著幾個核心。
比如,雙核就是包括2個相對獨立的CPU核心單元組,四核就包含4個相對獨立的CPU核心單元組
CPU的執行緒數:
對於一個CPU,執行緒數總是大於或等於核心數的。
(1)一個核心最少對應一個執行緒,但透過超執行緒技術,一個核心可以對應兩個執行緒,也就是說它可以同時執行兩個執行緒。
(2)CPU之所以要增加執行緒數,是源於多工處理的需要。執行緒數越多,越有利於同時執行多個程式,因為執行緒數等同於在某個瞬間CPU能同時並行處理的任務數。
eg:
在Windows中,在cmd命令中輸入“wmic”,然後在出現的新視窗中輸入“cpu get *”即可檢視物理CPU數、CPU核心數、執行緒數。
其中:
Name:表示物理CPU數
NumberOfCores:表示CPU核心數
NumberOfLogicalProcessors:表示CPU執行緒數
(1)CPU的執行緒數概念僅僅只針對Intel的CPU才有用,因為它是透過Intel超執行緒技術來實現的
(2)如果沒有超執行緒技術,一個CPU核心對應一個執行緒。 所以,對於AMD的CPU來說,只有核心數的概念,沒有執行緒數的概念。
在Windows中,在cmd命令中輸入“wmic”,然後在出現的新視窗中輸入“cpu get *”即可檢視物理CPU數、CPU核心數、執行緒數。
其中:
Name:表示物理CPU數
NumberOfCores:表示CPU核心數
NumberOfLogicalProcessors:表示CPU執行緒數
(1)CPU的執行緒數概念僅僅只針對Intel的CPU才有用,因為它是透過Intel超執行緒技術來實現的
(2)如果沒有超執行緒技術,一個CPU核心對應一個執行緒。 所以,對於AMD的CPU來說,只有核心數的概念,沒有執行緒數的概念。
3.是否使用執行緒池就一定比使用單執行緒高效呢?
答案是否定的,比如Redis就是單執行緒的,但它卻非常高效,基本操作都能達到十萬量級/s。從執行緒這個角度來看,部分原因在於:
(1)多執行緒帶來執行緒上下文切換開銷,單執行緒就沒有這種開銷
(2)鎖,當然“Redis很快”更本質的原因在於:
Redis基本都是記憶體操作,這種情況下單執行緒可以很高效地利用CPU。而多執行緒適用場景一般是:存在相當比例的IO和網路操作。
所以即使有上面的簡單估算方法,也許看似合理,但實際上也未必合理,都需要結合系統真實情況(比如是IO密集型或者是CPU密集型或者是純記憶體操作)和硬體環境(CPU、記憶體、硬碟讀寫速度、網路狀況等)來不斷嘗試達到一個符合實際的合理估算值。