並發下線程池的最佳數量計算


在高並發的情況下采用線程池,有效的降低了線程創建釋放的時間花銷及資源開銷,如不使用線程池,有可能造成系統創建大量線程而導致消耗完系統內存以及”過度切換”。(在JVM中采用的處理機制為時間片輪轉,減少了線程間的相互切換)
那么在高並發的情況下,我們怎么選擇最優的線程數量呢?選擇原則又是什么呢?這個問題去哪網的技術總監問過我,這里總結一下。
第一種:

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

如果是IO密集型應用,則線程池大小設置為2N+1

   
   
  
  
          

任務一般可分為:CPU密集型、IO密集型、混合型,對於不同類型的任務需要分配不同大小的線程池。CPU密集型任務 盡量使用較小的線程池,一般為CPU核心數+1。 因為CPU密集型任務使得CPU使用率很高,若開過多的線程數,只能增加上下文切換的次數,因此會帶來額外的開銷。IO密集型任務 可以使用稍大的線程池,一般為2*CPU核心數。 IO密集型任務CPU使用率並不高,因此可以讓CPU在等待IO的時候去處理別的任務,充分利用CPU時間。混合型任務 可以將任務分成IO密集型和CPU密集型任務,然后分別用不同的線程池去處理。 只要分完之后兩個任務的執行時間相差不大,那么就會比串行執行來的高效。 因為如果划分之后兩個任務執行時間相差甚遠,那么先執行完的任務就要等后執行完的任務,最終的時間仍然取決於后執行完的任務,而且還要加上任務拆分與合並的開銷,得不償失。

第二種呢,先由之前遇到的一個測試題說起,假設要求一個系統的TPS(Transaction Per Second或者Task Per Second)至少為20,然后假設每個Transaction由一個線程完成,繼續假設平均每個線程處理一個Transaction的時間為4s。那么問題轉化為:

如何設計線程池大小,使得可以在1s內處理完20個Transaction?

計算過程很簡單,每個線程的處理能力為0.25TPS,那么要達到20TPS,顯然需要20/0.25=80個線程。
這個理論上成立的,但是實際情況中,一個系統最快的部分是CPU,所以決定一個系統吞吐量上限的是CPU。增強CPU處理能力,可以提高系統吞吐量上限。在考慮時需要把CPU吞吐量加進去。在IO優化文檔中,有這樣地公式:
最佳線程數目 = ((線程等待時間+線程CPU時間)/線程CPU時間 )* CPU數目
即線程等待時間所占比例越高,需要越多線程。線程CPU時間所占比例越高,需要越少線程。
但根據短板效應,真實的系統吞吐量並不能單純根據CPU來計算。那要提高系統吞吐量,就需要從“系統短板”(比如網絡延遲、IO)着手:

盡量提高短板操作的並行化比率,比如多線程下載技術
增強短板能力,比如用NIO替代IO


盡量提高短板操作的並行化比率,比如多線程下載技術
增強短板能力,比如用NIO替代IO

   
   
  
  
          

第一條可以聯系到Amdahl定律,這條定律定義了串行系統並行化后的加速比計算公式:

加速比=優化前系統耗時 / 優化后系統耗時

   
   
  
  
          

加速比越大,表明系統並行化的優化效果越好。Addahl定律還給出了系統並行度、CPU數目和加速比的關系,加速比為Speedup,系統串行化比率(指串行執行代碼所占比率)為F,CPU數目為N:

Speedup <= 1 / (F + (1-F)/N)

   
   
  
  
          

當N足夠大時,串行化比率F越小,加速比Speedup越大。

這時候又拋出是否線程池一定比但線程高效的問題?

答案是否定的,比如Redis就是單線程的,但它卻非常高效,基本操作都能達到十萬量級/s。從線程這個角度來看,部分原因在於:

多線程帶來線程上下文切換開銷,單線程就沒有這種開銷
鎖

   
   
  
  
          

當然“Redis很快”更本質的原因在於:
Redis基本都是內存操作,這種情況下單線程可以很高效地利用CPU。而多線程適用場景一般是:存在相當比例的IO和網絡操作。

總的來說,應用情況不同,采取多線程/單線程策略不同;線程池情況下,不同的估算,目的和出發點是一致的。

參考借鑒:http://ifeve.com/how-to-calculate-threadpool-size/
https://www.zhihu.com/question/38128980
相互學習,共同進步!


免責聲明!

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



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