1. 程式人生 > >如何合理地估算執行緒池大小?

如何合理地估算執行緒池大小?

 這個問題雖然看起來很小,卻並不那麼容易回答。大家如果有更好的方法歡迎賜教,^_^

    先來一個天真的估算方法:假設要求一個系統的TPS(Transaction Per Second或者Task Per Second)至少為20,然後假設每個Transaction由一個執行緒完成,繼續假設平均每個執行緒處理一個Transaction的時間為4s。那麼問題轉化為:

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

    計算過程很簡單,每個執行緒的處理能力為0.25TPS,那麼要達到20TPS,顯然需要20/0.25=80個執行緒。

    很顯然這個估算方法很天真,因為它沒有考慮到CPU數目。一般伺服器的CPU核數為16或者32,如果有80個執行緒,那麼肯定會帶來太多不必要的執行緒上下文切換開銷。

    再來第二種簡單的但不知是否可行的方法(N為CPU總核數):

  • 如果是CPU密集型應用,則執行緒池大小設定為N+1
  • 如果是IO密集型應用,則執行緒池大小設定為2N+1

    如果一臺伺服器上只部署了這一個應用並且只有這一個執行緒池,那麼這種估算或許合理,具體還需自行測試驗證。

    接下來在這個文件:伺服器效能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數目

    可以得出一個結論:

1 執行緒等待時間所佔比例越高,需要越多執行緒。
2 執行緒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、記憶體、硬碟讀寫速度、網路狀況等)來不斷嘗試達到一個符合實際的合理估算值。

    最後來一個“Dark Magic”估算方法(因為我暫時還沒有搞懂它的原理),使用下面的類:

001 package pool_size_calculate;
002
003 import java.math.BigDecimal;
004 import java.math.RoundingMode;
005 import java.util.Timer;
006 import java.util.TimerTask;
007 import java.util.concurrent.BlockingQueue;
008
009 /**
010 * A class that calculates the optimal thread pool boundaries. It takes the
011 * desired target utilization and the desired work queue memory consumption as
012 * input and retuns thread count and work queue capacity.
013 *
014 * @author Niklas Schlimm
015 *
016 */
017 public abstract class PoolSizeCalculator {
018
019 /**
020 * The sample queue size to calculate the size of a single {@link Runnable}
021 * element.
022 */
023 private final int SAMPLE_QUEUE_SIZE = 1000;
024
025 /**
026 * Accuracy of test run. It must finish within 20ms of the testTime
027 * otherwise we retry the test. This could be configurable.
028 */
029 private final int EPSYLON = 20;
030
031 /**
032 * Control variable for the CPU time investigation.
033 */
034

相關推薦

如何合理估算執行大小

 這個問題雖然看起來很小,卻並不那麼容易回答。大家如果有更好的方法歡迎賜教,^_^     先來一個天真的估算方法:假設要求一個系統的TPS(Transaction Per Second或者Task Per Second)至少為20,然後假設每個Transaction由一個執行緒完成,繼續假設平均每個執行緒

java合理估算執行大小——Dark Magic

具體見併發程式設計網的文章http://ifeve.com/how-to-calculate-threadpool-size/, 原始碼亂序了,這裡做一個排序後分享 github地址: https://github.com/sunshanpeng/dark_magic

如何合理設定執行大小

要想合理的配置執行緒池的大小,首先得分析任務的特性,可以從以下幾個角度分析: 任務的性質:CPU密集型任務、IO密集型任務、混合型任務。 任務的優先順序:高、中、低。 任務的執行時間:長、中、短。 任務的依賴性:是否依賴其他系統資源,如資料庫連線等。 性質不同的任務可

合理設定執行大小

開發十年,就只剩下這套架構體系了! >>>   

根據CPU核數合理設定執行大小

    自定義執行緒池程式碼 package com.lc.concurrent; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; i

Java多執行-----執行的使用,原理以及舉例實現(三)(四):使用樣例及如何配置執行大小

三.使用示例   前面我們討論了關於執行緒池的實現原理,這一節我們來看一下它的具體使用: public class Test { public static void main(String[] args) { ThreadPoolExe

通俗易懂理解執行&&C++程式碼例項與講解

本機環境:win10   64位   vs2017 C++新手,程式碼寫得比較一般,高手見諒(抱拳)。 歡迎留言交流! 簡介執行緒池: 在介紹執行緒池之前,我們要首先知道多執行緒是啥。 單執行緒:就是說你現在有四件毫不相干的事情要分

執行大小設定,CPU的核心數、執行數的關係和區別,同步與堵塞完全是兩碼事

執行緒池應該設定多少執行緒合適,怎麼樣估算出來。最近接觸到一些相關資料,現作如下總結。 最開始接觸執行緒池的時候,沒有想到就僅僅是設定一個執行緒池的大小居然還有這麼多的學問,汗顏啊。 首先,需要考慮到執行緒池所進行的工作的性質: IO密集型 CPU密集型 簡單的分析來看,如果是CPU密集

如何決定 Web 應用的執行大小

在部署 web 應用到生產環境,或者在對 web 應用進行效能測試的時候,經常會有人問:如何決定 web 應用執行緒池大小?決定一個 IO 阻塞型 web 應用的執行緒池大小是一項很艱鉅的任務。通常是通過進行大量的效能測試來完成。在一個 web 應用中同時擁有多個執行緒池會讓

ThreadPoolExecutor使用和思考(上)-執行大小設定與BlockingQueue的三種實現區別

工作中多處接觸到了ThreadPoolExecutor。趁著現在還算空,學習總結一下。 前記: jdk官方文件(javadoc)是學習的最好,最權威的參考。文章分上中下。上篇中主要介紹ThreadPoolExecutor接受任務相關的兩方面入參的意義和區別,池大小引

ThreadPoolExecutor執行大小設定

最近用到ThreadPoolExecutor ,想到這個問題; 下面是從網上找到的。 執行緒池的理想大小取決於被提交任務的型別以及所部署系統的特性。執行緒池應該避免設定的過大或過小,如果執行緒池過大,大量的執行緒將在相對很少的CPU和記憶體資源上發生競爭,這不僅

如何用利特爾法則調整執行大小

## 利特爾法則 利特爾法則派生於**排隊論**,用以下數學公式表示: L = λW L 系統中存在的平均請求數量。 λ 請求有效到達速率。例如:5/s 表示每秒有5個請求到達系統。 W 請求在系統中的平均等待執行時間。 > 排隊論:研究服務系統中排隊現象隨機規律的學科,探究排隊有關的數

1000個併發執行,10臺機器,每臺機器4核,設計執行大小

這是why哥的第 71 篇原創文章 一道面試題 兄弟們,怎麼說? 我覺得如果你工作了兩年左右的時間,或者是突擊準備了面試,這題回答個八成上來,應該是手到擒來的事情。這題中規中矩,考點清晰,可以說的東西不是很多。 但是這都上血書了,那不得分析一波? 先把這個面試題拿出來一下: 1000 多個併發執行緒,10

如何合理確定執行大小

在java中,幾乎所有需要非同步或者併發執行任務的程式都可以使用執行緒池。在開發過程中,合理的使用執行緒池能夠帶來3個好處 首先是降低資源消耗。通過重複利用已建立的執行緒降低建立執行緒和銷燬執行緒所帶來的開銷。 提高相應速度。當任務到達時,任務可以不需要等待

017.多執行-執行原理解析以及合理配置

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveT

使用無限大小執行 newCachedThreadPool 可能遇到的問題

看一段測試程式碼:  [java] view plain copy  print? package com.wenniuwuren.concurrent;   import java.util.concurrent.ExecutorService;   i

ExecutorService常用方法和newFixedThreadPool建立固定大小執行

1、ExecutorService: 是一個介面,繼承了Executor: public interface ExecutorService extends Executor { } 2、Executor: 而Executor亦是一個介面,該介面只包含了一個方法: void exe

java執行學習(六) —— 執行合理配置

一、確定執行緒數 在工作中,為了加快程式的處理速度,我們需要將問題分解成若干個併發執行的任務。接著我們將這些任務委派給執行緒,以便使它們可以併發的執行。但是需要注意的是,由於資源所限,我們不能建立過多

[C++]固定大小執行

執行緒池模型 執行緒池是併發程式設計中常用的模型。 執行緒是一種非常寶貴的資源,建立、銷燬執行緒都是非常消耗時間的操作,所以我們的一個思路是在程式start up的時候,建立一個儲存有多個執行緒的快取,這樣程式執行時就不會頻繁的發生建立和銷燬執行緒的操作,從

通俗易懂給女朋友講:執行的內部原理

餐廳的約會 餐盤在燈光的照耀下格外晶瑩潔白,女朋友拿起紅酒杯輕輕地抿了一小口,對我說:“經常聽你說執行緒池,到底執行緒池到底是個什麼原理?”我楞了一下,心裡想女朋友今天是怎麼了,怎麼突然問出這麼專業的問題,但做為一個專業人士在女朋友面前也不能露怯啊,想了一下便說:“我先給你講講我前同事老王的故事吧!”歡迎