自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java線程:創(chuàng)建多少線程才是合適的?

開發(fā) 前端
很多人都知道線程數(shù)不是越多越好,但是設置多少是合適的,卻又拿不定主意。其實只要把握住一條原則就可以了,這條原則就是將硬件的性能發(fā)揮到極致。上面我們針對 CPU 密集型和 I/O 密集型計算場景都給出了理論上的最佳公式,這些公式背后的目標其實就是將硬件的性能發(fā)揮到極致。

在 Java 領域,實現(xiàn)并發(fā)程序的主要手段就是多線程,使用多線程還是比較簡單的,但是使用多少個線程卻是個困難的問題。工作中,經(jīng)常有人問,“各種線程池的線程數(shù)量調(diào)整成多少是合適的?”或者“Tomcat 的線程數(shù)、Jdbc 連接池的連接數(shù)是多少?”等等。那我們應該如何設置合適的線程數(shù)呢?

要解決這個問題,首先要分析以下兩個問題:

  1. 為什么要使用多線程?
  2. 多線程的應用場景有哪些?

為什么要使用多線程?

使用多線程,本質(zhì)上就是提升程序性能。不過此刻談到的性能,可能在你腦海里還是比較籠統(tǒng)的,基本上就是快、快、快,這種無法度量的感性認識很不科學,所以在提升性能之前,首要問題是:如何度量性能。

度量性能的指標有很多,但是有兩個指標是最核心的,它們就是延遲和吞吐量。延遲指的是發(fā)出請求到收到響應這個過程的時間;延遲越短,意味著程序執(zhí)行得越快,性能也就越好。 吞吐量指的是在單位時間內(nèi)能處理請求的數(shù)量;吞吐量越大,意味著程序能處理的請求越多,性能也就越好。這兩個指標內(nèi)部有一定的聯(lián)系(同等條件下,延遲越短,吞吐量越大),但是由于它們隸屬不同的維度(一個是時間維度,一個是空間維度),并不能互相轉(zhuǎn)換。

我們所謂提升性能,從度量的角度,主要是降低延遲,提高吞吐量。這也是我們使用多線程的主要目的。那我們該怎么降低延遲,提高吞吐量呢?這個就要從多線程的應用場景說起了。

多線程的應用場景

要想“降低延遲,提高吞吐量”,對應的方法呢,基本上有兩個方向,一個方向是優(yōu)化算法,另一個方向是將硬件的性能發(fā)揮到極致。前者屬于算法范疇,后者則是和并發(fā)編程息息相關了。那計算機主要有哪些硬件呢?主要是兩類:一個是 I/O,一個是 CPU。簡言之,在并發(fā)編程領域,提升性能本質(zhì)上就是提升硬件的利用率,再具體點來說,就是提升 I/O 的利用率和 CPU 的利用率。

我們的并發(fā)程序,需要 CPU 和 I/O 設備相互配合工作,也就是說,我們需要解決 CPU 和 I/O 設備綜合利用率的問題。

下面我們用一個簡單的示例來說明:如何利用多線程來提升 CPU 和 I/O 設備的利用率?假設程序按照 CPU 計算和 I/O 操作交叉執(zhí)行的方式運行,而且 CPU 計算和 I/O 操作的耗時是 1:1。

如下圖所示,如果只有一個線程,執(zhí)行 CPU 計算的時候,I/O 設備空閑;執(zhí)行 I/O 操作的時候,CPU 空閑,所以 CPU 的利用率和 I/O 設備的利用率都是 50%。

單線程執(zhí)行示意圖單線程執(zhí)行示意圖

如果有兩個線程,如下圖所示,當線程 A 執(zhí)行 CPU 計算的時候,線程 B 執(zhí)行 I/O 操作;當線程 A 執(zhí)行 I/O 操作的時候,線程 B 執(zhí)行 CPU 計算,這樣 CPU 的利用率和 I/O 設備的利用率就都達到了 100%。

二線程執(zhí)行示意圖二線程執(zhí)行示意圖

我們將 CPU 的利用率和 I/O 設備的利用率都提升到了 100%,會對性能產(chǎn)生了哪些影響呢?通過上面的圖示,很容易看出:單位時間處理的請求數(shù)量翻了一番,也就是說吞吐量提高了 1 倍。此時可以逆向思維一下,如果 CPU 和 I/O 設備的利用率都很低,那么可以嘗試通過增加線程來提高吞吐量。

創(chuàng)建多少線程合適?

創(chuàng)建多少線程合適,要看多線程具體的應用場景。我們的程序一般都是 CPU 計算和 I/O 操作交叉執(zhí)行的,由于 I/O 設備的速度相對于 CPU 來說都很慢,所以大部分情況下,I/O 操作執(zhí)行的時間相對于 CPU 計算來說都非常長,這種場景我們一般都稱為 I/O 密集型計算;和 I/O 密集型計算相對的就是 CPU 密集型計算了,CPU 密集型計算大部分場景下都是純 CPU 計算。I/O 密集型程序和 CPU 密集型程序,計算最佳線程數(shù)的方法是不同的。

下面我們對這兩個場景分別說明。

對于 CPU 密集型計算,多線程本質(zhì)上是提升多核 CPU 的利用率,所以對于一個 4 核的 CPU,每個核一個線程,理論上創(chuàng)建 4 個線程就可以了,再多創(chuàng)建線程也只是增加線程切換的成本。所以,對于 CPU 密集型的計算場景,理論上“線程的數(shù)量 =CPU 核數(shù)”就是最合適的。不過在工程上,線程的數(shù)量一般會設置為“CPU 核數(shù) +1”,這樣的話,當線程因為偶爾的內(nèi)存頁失效或其他原因?qū)е伦枞麜r,這個額外的線程可以頂上,從而保證 CPU 的利用率。

對于 I/O 密集型的計算場景,比如前面我們的例子中,如果 CPU 計算和 I/O 操作的耗時是 1:1,那么 2 個線程是最合適的。如果 CPU 計算和 I/O 操作的耗時是 1:2,那多少個線程合適呢?是 3 個線程,如下圖所示:CPU 在 A、B、C 三個線程之間切換,對于線程 A,當 CPU 從 B、C 切換回來時,線程 A 正好執(zhí)行完 I/O 操作。這樣 CPU 和 I/O 設備的利用率都達到了 100%。

三線程執(zhí)行示意圖三線程執(zhí)行示意圖

通過上面這個例子,我們會發(fā)現(xiàn),對于 I/O 密集型計算場景,最佳的線程數(shù)是與程序中 CPU 計算和 I/O 操作的耗時比相關的,我們可以總結(jié)出這樣一個公式:

最佳線程數(shù) =1 +(I/O 耗時 / CPU 耗時)

我們令 R=I/O 耗時 / CPU 耗時,綜合上圖,可以這樣理解:當線程 A 執(zhí)行 IO 操作時,另外 R 個線程正好執(zhí)行完各自的 CPU 計算。這樣 CPU 的利用率就達到了 100%。

不過上面這個公式是針對單核 CPU 的,至于多核 CPU,也很簡單,只需要等比擴大就可以了,計算公式如下:

最佳線程數(shù) =CPU 核數(shù) * [ 1 +(I/O 耗時 / CPU 耗時)]

總結(jié)

很多人都知道線程數(shù)不是越多越好,但是設置多少是合適的,卻又拿不定主意。其實只要把握住一條原則就可以了,這條原則就是將硬件的性能發(fā)揮到極致。上面我們針對 CPU 密集型和 I/O 密集型計算場景都給出了理論上的最佳公式,這些公式背后的目標其實就是將硬件的性能發(fā)揮到極致。

對于 I/O 密集型計算場景,I/O 耗時和 CPU 耗時的比值是一個關鍵參數(shù),不幸的是這個參數(shù)是未知的,而且是動態(tài)變化的,所以工程上,我們要估算這個參數(shù),然后做各種不同場景下的壓測來驗證我們的估計。不過工程上,原則還是將硬件的性能發(fā)揮到極致,所以壓測時,我們需要重點關注 CPU、I/O 設備的利用率和性能指標(響應時間、吞吐量)之間的關系。

課后思考

有些開發(fā)人員對于最佳線程數(shù)的設置積累了一些經(jīng)驗值,認為對于 I/O 密集型應用,最佳線程數(shù)應該為:2 * CPU 的核數(shù) + 1,你覺得這個經(jīng)驗值合理嗎?

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2022-03-21 12:45:28

Java線程代碼

2010-03-18 15:31:13

Java創(chuàng)建線程

2010-03-15 17:56:23

Java多線程

2020-09-08 10:56:55

Java多線程存儲器

2009-06-29 17:54:10

Java多線程Thread類創(chuàng)建線程

2009-06-29 18:00:05

Java多線程Runnable接口創(chuàng)建線程

2023-12-20 10:04:45

線程池Java

2024-06-27 08:04:39

2019-10-10 11:50:38

Java線程開發(fā)

2022-03-14 08:02:08

輕量級動態(tài)線程池

2023-02-24 14:46:32

Java線程池編程

2010-03-18 15:47:07

Java創(chuàng)建線程

2020-06-16 11:00:40

線程Java代碼

2023-09-04 08:08:59

2023-08-28 07:39:49

線程調(diào)度基本單位

2024-11-06 08:49:46

2021-02-25 15:58:46

C++線程編程開發(fā)技術(shù)

2023-12-07 07:28:25

線程共享資源

2022-06-07 07:37:40

線程進程開發(fā)

2013-07-15 15:35:06

點贊
收藏

51CTO技術(shù)棧公眾號