這個問題雖然看起來很小,卻並不那麼容易回答。大家如果有更好的方法歡迎賜教,先來乙個天真的估算方法:假設要求乙個系統的tps(transaction per second或者task per second)至少為20,然後假設每個transaction由乙個執行緒完成,繼續假設平均每個執行緒處理乙個transaction的時間為4s。那麼問題轉化為:
如何設計執行緒池大小,使得可以在1s內處理完20個transaction?
計算過程很簡單,每個執行緒的處理能力為0.25tps,那麼要達到20tps,顯然需要20/0.25=80個執行緒。
很顯然這個估算方法很天真,因為它沒有考慮到cpu數目。一般伺服器的cpu核數為16或者32,如果有80個執行緒,那麼肯定會帶來太多不必要的執行緒上下文切換開銷。
再來第二種簡單的但不知是否可行的方法(n為cpu總核數):
如果一台伺服器上只部署這乙個應用並且只有這乙個執行緒池,那麼這種估算或許合理,具體還需自行測試驗證。
接下來在這個文件:伺服器效能io優化 中發現乙個估算公式:
1
最佳執行緒數目 = ((執行緒等待時間+執行緒cpu時間)/執行緒cpu時間 )* cpu數目
比如平均每個執行緒cpu執行時間為0.5s,而執行緒等待時間(非cpu執行時間,比如io)為1.5s,cpu核心數為8,那麼根據上面這個公式估算得到:((0.5+1.5)/0.5)*8=32。這個公式進一步轉化為:
1
最佳執行緒數目 = (執行緒等待時間與執行緒cpu時間之比 + 1)* cpu數目
可以得出乙個結論:
執行緒等待時間所佔比例越高,需要越多執行緒。執行緒cpu時間所佔比例越高,需要越少執行緒。
上一種估算方法也和這個結論相合。
乙個系統最快的部分是cpu,所以決定乙個系統吞吐量上限的是cpu。增強cpu處理能力,可以提高系統吞吐量上限。但根據短板效應,真實的系統吞吐量並不能單純根據cpu來計算。那要提高系統吞吐量,就需要從「系統短板」(比如網路延遲、io)著手:
增強短板能力,比如用nio替代io
第一條可以聯絡到amdahl定律,這條定律定義了序列系統並行化後的加速比計算公式:
1
加速比=優化前系統耗時 / 優化後系統耗時
加速比越大,表明系統並行化的優化效果越好。addahl定律還給出了系統並行度、cpu數目和加速比的關係,加速比為speedup,系統序列化比率(指序列執行**所佔比率)為f,cpu數目為n:
1
speedup <=
1
/ (f + (
1
-f)/n)
當n足夠大時,序列化比率f越小,加速比speedup越大。
寫到這裡,我突然冒出乙個問題。
是否使用執行緒池就一定比使用單執行緒高效呢?
答案是否定的,比如redis就是單執行緒的,但它卻非常高效,基本操作都能達到十萬量級/s。從執行緒這個角度來看,部分原因在於:
當然「redis很快」更本質的原因在於:redis基本都是記憶體操作,這種情況下單執行緒可以很高效地利用cpu。而多執行緒適用場景一般是:存在相當比例的io和網路操作。
所以即使有上面的簡單估算方法,也許看似合理,但實際上也未必合理,都需要結合系統真實情況(比如是io密集型或者是cpu密集型或者是純記憶體操作)和硬體環境(cpu、記憶體、硬碟讀寫速度、網路狀況等)來不斷嘗試達到乙個符合實際的合理估算值。
如何合理地估算執行緒池大小?
如何合理設定執行緒池大小
要想合理的配置執行緒池的大小,首先得分析任務的特性,可以從以下幾個角度分析 任務的性質 cpu密集型任務 io密集型任務 混合型任務。任務的優先順序 高 中 低。任務的依賴性 是否依賴其他系統資源,如資料庫連線等。性質不同的任務可以交給不同規模的執行緒池執行。對於不同性質的任務來說,cpu密集型任務...
如何合理設定執行緒池大小
要想合理的配置執行緒池的大小,首先得分析任務的特性,可以從以下幾個角度分析 任務的性質 cpu密集型任務 io密集型任務 混合型任務。任務的優先順序 高 中 低。任務的依賴性 是否依賴其他系統資源,如資料庫連線等。性質不同的任務可以交給不同規模的執行緒池執行。對於不同性質的任務來說,cpu密集型任務...
java執行緒池如何合理的設定大小
任務一般分為 cpu密集型 io密集型 混合型,對於不同型別的任務需要分配不同大小的執行緒池 1 cpu密集型 盡量使用較小的執行緒池,一般cpu核心數 1 因為cpu密集型任務cpu的使用率很高,若開過多的執行緒,只能增加執行緒上下文的切換次數,帶來額外的開銷 2 io密集型 方法一 可以使用較大...