1. CPU 密集型(I/O bound)
CPU密集型也叫計算密集型,指的是系統的硬盤、內存性能相對CPU要好很多,此時,系統運作大部分的狀況是CPU Loading 100%,CPU要讀/寫I/O(硬盤/內存),I/O在很短的時間就可以完成,而CPU還有許多運算要處理,CPU Loading很高。
CPU密集的意思是該任務需要大量的運算,而沒有阻塞,CPU一直全速運行。CPU密集任務只有在真正的多核CPU上才可能得到加速(通過多線程),而在單核CPU上,無論你開幾個模擬的多線程該任務都不可能得到加速,因為CPU總的運算能力就那些。
CPU 使用率較高(例如:計算一些復雜的運算,邏輯處理等情況)非常多的情況下,線程數一般只需要設置為CPU核心數的線程個數就可以了。 這一類型多出現在開發中的一些業務復雜計算和邏輯處理過程中。
2. I/O 密集型(I/O bound)
IO密集型指的是系統的CPU性能相對硬盤、內存要好很多,此時,系統運作,大部分的狀況是CPU在等I/O (硬盤/內存) 的讀/寫操作,此時CPU Loading並不高。I/O bound的程序一般在達到性能極限時,CPU占用率仍然較低。這可能是因為任務本身需要大量I/O操作,而pipeline做得不是很好,沒有充分利用處理器能力。
CPU 使用率較低,程序中會存在大量的 I/O 操作占用時間,導致線程空余時間很多,所以通常就需要開CPU核心數兩倍的線程。當線程進行 I/O 操作 CPU 空閑時,啟用其他線程繼續使用 CPU,以提高 CPU 的使用率。例如:數據庫交互,文件上傳下載,網絡傳輸等。
線程等待時間所占比例越高,需要越多線程,啟用其他線程繼續使用CPU,以此提高CPU的利用率;線程 CPU 時間所占比例越高,需要越少的線程,這一類型在開發中主要出現在一些計算業務頻繁的邏輯中。
方法一:
由於IO密集型任務線程並不是一直在執行任務,則應配置盡可能多的線程,如CPU核數*2
方法二:
IO密集型,即該任務需要大量的IO,即大量的阻塞。在單線程上運IO密集型的任務會導致浪費大量的CPU運算能力浪費在等待。所以在IO密集型任務中使用多線程可以大大的加速程序運行,即使在單核CPU上,這種加速主要就是利用了被浪費掉的阻塞時間。
IO密集型時,大部分線程都阻塞,故需要多配置線程數:
參考公式:CPU核數 /(1 - 阻系數)
比如8核CPU:8/(1 - 0.9)=80個線程數
阻塞系數在0.8~0.9之間
3. 混合型
即TaskQueue中既有計算型的Task也有IO型的Task,
3.1 計算公式一
所以為了正確設置線程池的大小,我們應該計算出 我們的計算型任務(用 C表示)占總任務的比例(總任務個數=計算型任務個數+阻塞型任務個數(用W表示))
假設當前 CPU 的核數 為 N = 4。
rate = C/(C+W)
這樣 CORE_SIZE = N/rate。
如 當前有8個計算型任務,2個阻塞型任務,比例就是 0.8,也就是4/5,計算可得 CORE_SIZE = 5 時,能最大程度的利用 CPU。
如 當前有8個計算型任務,8個全是計算型任務,比例就是 1,也就是5/5,計算可得 CORE_SIZE = 4 時,能最大程度的利用 CPU。
3.2 計算公式二(抄自 Java 並發編程實戰)
4. 總結:
1.一個計算為主的程序(CPU密集型程序),多線程跑的時候,可以充分利用起所有的 CPU 核心數,比如說 8 個核心的CPU ,開8 個線程的時候,可以同時跑 8 個線程的運算任務,此時是最大效率。但是如果線程遠遠超出 CPU 核心數量,反而會使得任務效率下降,因為頻繁的切換線程也是要消耗時間的。因此對於 CPU 密集型的任務來說,線程數等於 CPU 數是最好的了。
2.如果是一個磁盤或網絡為主的程序(IO密集型程序),一個線程處在 IO 等待的時候,另一個線程還可以在 CPU 里面跑,有時候 CPU 閑着沒事干,所有的線程都在等着 IO,這時候他們就是同時的了,而單線程的話此時還是在一個一個等待的。我們都知道 IO 的速度比起 CPU 來是很慢的。此時線程數等於CPU核心數的兩倍是最佳的。
5. 核心線程數計算公式
IO密集型:核心線程數 = CPU核數 / (1-阻塞系數)
IO密集型:核心線程數 = CPU核數 * 2
CPU密集型:核心線程數 = CPU核數 + 1
混合型:核心線程數 = CPU核數/CPU密集型占比系數。
6. 核心線程數 = CPU核數 + 1,為什么要加1?
當線程池的大小為1 時,能實現 CPU 的最優利用率。即使當計算密集型的線程 偶爾由於頁缺失故障或者其他原因暫停時,這個“額外” 的線程也能確保CPU 的時裝周期不會被浪費。