java統計系統線程數_Java并發(八)計算線程池最佳線程數

目錄

一、理論分析

二、實際應用

為了加快程序處理速度,我們會將問題分解成若干個并發執行的任務。并且創建線程池,將任務委派給線程池中的線程,以便使它們可以并發地執行。在高并發的情況下采用線程池,可以有效降低線程創建釋放的時間花銷及資源開銷,如不使用線程池,有可能造成系統創建大量線程而導致消耗完系統內存以及“過度切換”(在JVM中采用的處理機制為時間片輪轉,減少了線程間的相互切換)?。

但是有一個很大的問題擺在我們面前,即我們希望盡可能多地創建任務,但由于資源所限我們又不能創建過多的線程。那么在高并發的情況下,我們怎么選擇最優的線程數量呢?選擇原則又是什么呢?

一、理論分析

關于如何計算并發線程數,有兩種說法。

第一種,《Java Concurrency in Practice》即《java并發編程實踐》8.2節 170頁

對于計算密集型的任務,一個有Ncpu個處理器的系統通常通過使用一個Ncpu+ 1個線程的線程池來獲得最優的利用率(計算密集型的線程恰好在某時因為發生一個頁錯誤或者因其他原因而暫停,剛好有一個“額外”的線程,可以確保在這種情況下CPU周期不會中斷工作)。對于包含了 I/O和其他阻塞操作的任務,不是所有的線程都會在所有的時間被調度,因此你需要一個更大的池。為了正確地設置線程池的長度,你必須估算出任務花在等待的時間與用來計算的時間的比率;這個估算值不必十分精確,而且可以通過一些監控工具獲得。你還可以選擇另一種方法來調節線程池的大小,在一個基準負載下,使用 幾種不同大小的線程池運行你的應用程序,并觀察CPU利用率的水平。

給定下列定義:

Ncpu?=?CPU的數量

Ucpu?= 目標CPU的使用率, 0 <=?Ucpu?<= 1

W/C?= 等待時間與計算時間的比率

為保持處理器達到期望的使用率,最優的池的大小等于:

Nthreads?=?Ncpu?x?Ucpu?x (1 +?W/C)

你可以使用Runtime來獲得CPU的數目:

int N_CPUS = Runtime.getRuntime().availableProcessors();

當然,CPU周期并不是唯一你可以使用線程池管理的資源。其他可以約束資源池大小的資源包括:內存、文件句柄、套接字句柄和數據庫連接等。計算這些類型資源池的大小約束非常簡單:首先累加出每一個任務需要的這些資源的總童,然后除以可用的總量。所 得的結果是池大小的上限。

當任務需要使用池化的資源時,比如數據庫連接,那么線程池的長度和資源池的長度會相互影響。如果每一個任務都需要一個數據庫連接,那么連接池的大小就限制了線程池的有效大小;類似地,當線程池中的任務是連接池的唯一消費者時,那么線程池的大小反而又會限制了連接池的有效大小。

如上,在《Java Concurrency in Practice》一書中,給出了估算線程池大小的公式:

Nthreads?=?Ncpu?x?Ucpu?x (1 +?W/C),其中

Ncpu?=?CPU核心數

Ucpu?=?CPU使用率,0~1

W/C?= 等待時間與計算時間的比率

第二種,《Programming Concurrency on the JVM Mastering》即《Java 虛擬機并發編程》2.1節 12頁

為了解決上述難題,我們希望至少可以創建處理器核心數那么多個線程。這就保證了有盡可能多地處理器核心可以投入到解決問題的工作中去。通過下面的代碼,我們可以很容易地獲取到系統可用的處理器核心數:

Runtime.getRuntime().availableProcessors();

所以,應用程序的最小線程數應該等于可用的處理器核數。如果所有的任務都是計算密集型的,則創建處理器可用核心數那么多個線程就可以了。在這種情況下,創建更多的線程對程序性能而言反而是不利的。因為當有多個仟務處于就緒狀態時,處理器核心需要在線程間頻繁進行上下文切換,而這種切換對程序性能損耗較大。但如果任務都是IO密集型的,那么我們就需要開更多的線程來提高性能。

當一個任務執行IO操作時,其線程將被阻塞,于是處理器可以立即進行上下文切換以便處理其他就緒線程。如果我們只有處理器可用核心數那么多個線程的話,則即使有待執行的任務也無法處理,因為我們已經拿不出更多的線程供處理器調度了。

如果任務有50%的時間處于阻塞狀態,則程序所需線程數為處理器可用核心數的兩倍。 如果任務被阻塞的時間少于50%,即這些任務是計算密集型的,則程序所需線程數將隨之減少,但最少也不應低于處理器的核心數。如果任務被阻塞的時間大于執行時間,即該任務是IO密集型的,我們就需要創建比處理器核心數大幾倍數量的線程。

我們可以計算出程序所需線程的總數,總結如下:

線程數 = CPU可用核心數/(1 - 阻塞系數),其中阻塞系數的取值在0和1之間。

計算密集型任務的阻塞系數為0,而IO密集型任務的阻塞系數則接近1。一個完全阻塞的任務是注定要掛掉的,所以我們無須擔心阻塞系數會達到1。

為了更好地確定程序所需線程數,我們需要知道下面兩個關鍵參數:

處理器可用核心數;

任務的阻塞系數;

第一個參數很容易確定,我們甚至可以用之前的方法在運行時查到這個值。但確定阻塞系數就稍微困難一些。我們可以先試著猜測,抑或采用一些性能分析工具或java.lang.management API來確定線程花在系統IO操作上的時間與CPU密集任務所耗時間的比值。

如上,在《Programming Concurrency on the JVM Mastering》一書中,給出了估算線程池大小的公式:

線程數 = Ncpu/(1 - 阻塞系數)

對于說法一,假設CPU 100%運轉,即撇開CPU使用率這個因素,線程數 = Ncpu?x (1 + W/C)。

現在假設將方法二的公式等于方法一公式,即Ncpu?/(1 - 阻塞系數)= Ncpu?x (1 + W/C),推導出:阻塞系數 = W / (W + C),即阻塞系數 = 阻塞時間 /(阻塞時間 + 計算時間),這個結論在方法二后續中得到印證,如下:

由于對Web服務的請求大部分時間都花在等待服務器響應上了,所以阻塞系數會相當高,因此程序需要開的線程數可能是處理器核心數的若干倍。假設阻塞系數是0.9,即每個任務90%的時間處于阻塞狀態而只有10%的時間在干活,則在雙核處理器上我們就需要開20個線程(使用第2.1節的公式計算)。如果有很多只股票要處理的話,我們可以在8核處理器上開到80個線程來處理該任務。

由此可見,說法一和說法二其實是一個公式。

二、實際應用

那么實際使用中并發線程數如何設置呢?我們先看一道題目:

假設要求一個系統的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吞吐量加進去。

分析如下(我們以說法一公式為例):

Nthreads?=?Ncpu?x (1 +?W/C)

即線程等待時間所占比例越高,需要越多線程。線程CPU時間所占比例越高,需要越少線程。這就可以劃分成兩種任務類型:

IO密集型:一般情況下,如果存在IO,那么肯定W/C > 1(阻塞耗時一般都是計算耗時的很多倍),但是需要考慮系統內存有限(每開啟一個線程都需要內存空間),這里需要在服務器上測試具體多少個線程數適合(CPU占比、線程數、總耗時、內存消耗)。如果不想去測試,保守點取1即可,Nthreads?= Ncpu?x (1 + 1) = 2Ncpu。這樣設置一般都OK。

計算密集型:假設沒有等待W = 0,則W/C = 0。 Nthreads?= Ncpu。

根據短板效應,真實的系統吞吐量并不能單純根據CPU來計算。那要提高系統吞吐量,就需要從“系統短板”(比如網絡延遲、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和網絡操作。

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

至此結論為:

IO密集型 = 2Ncpu(可以測試后自己控制大小,2Ncpu一般沒問題)(常出現于線程中:數據庫數據交互、文件上傳下載、網絡數據傳輸等等)

計算密集型 = Ncpu(常出現于線程中:復雜算法)

當然說法一中還有一種說法:

對于計算密集型的任務,一個有Ncpu個處理器的系統通常通過使用一個Ncpu+ 1個線程的線程池來獲得最優的利用率(計算密集型的線程恰好在某時因為發生一個頁錯誤或者因其他原因而暫停,剛好有一個“額外”的線程,可以確保在這種情況下CPU周期不會中斷工作)。

即,計算密集型 = Ncpu?+ 1,但是這種做法導致的多一個CPU上下文切換是否值得,這里不考慮。讀者可自己考量。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457237.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457237.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457237.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

php大小寫轉換函數

1.將字符串轉換成小寫 strtolower(): 該函數將傳入的字符串參數所有的字符都轉換成小寫,并以小定形式放回這個字 符串.例: <?php$str "I want To FLY";$str strtolower($str);echo $str; ?>輸出結果: i want to fly 2.將字符轉成大寫 strtoupper(): 該…

關于移動端 1px 像素問題

移動端1px變粗的原因 移動端html的header總會有一句<meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalableno">這句話定義了本頁面的viewport的寬度為設備寬度,初始縮放值和最大縮放值都為1,并禁止了…

java框架概念_java概念(2)

java概念(2)重載和重寫重載&#xff1a;同一個類中&#xff0c;方法名相同&#xff0c;參數不同重寫&#xff1a;父子類中&#xff0c;子類重新定義父類的方法多態? 多態&#xff1a;同一種行為&#xff0c;不同的對象有不同的表現形式。? 重載 編譯時根據參數決定調用的方法…

CentOS(八)--crontab命令的使用方法

crontab命令常見于Unix和Linux的操作系統之中&#xff0c;用于設置周期性被執行的指令。該命令從標準輸入設備讀取指令&#xff0c;并將其存放于"crontab"文件中&#xff0c;以供之后讀取和執行。 在Linux系統中&#xff0c;Linux任務調度的工作主要分為以下兩類&…

有健忘癥嗎?

今天興高采烈&#xff0c;早上空氣不錯&#xff0c; 但是騎自行車的我&#xff0c;還是得戴一個面罩。 半個小時后買了早餐&#xff0c; 一份炒粉、一豆漿&#xff0c;今天早上豆漿沒有掉地上&#xff0c; 但是~~~~~~~~~~~~~~shit~~!~!~,居然忘記帶要換的衣服了&#xff0c; …

下載java后綴的文件閃退_關于jarfile 打開閃退問題

后面才發現&#xff0c;原來是因為我把文件拖入了新建的文件夾&#xff0c;改變了路徑&#xff0c;而且我的java環境沒有配置好是全局變量&#xff0c;所以新建文件夾之后&#xff0c;就會出現找不到了路徑&#xff0c;閃退的問題&#xff0c;&#xff0c;&#xff0c;還有就是…

心理學資源整理

http://blog.sina.com.cn/s/articlelist_1227187337_0_1.html 功夫 轉載2016-06-07 15:53:55中華大地的武學&#xff0c;奧妙精深。但從大的方面來說&#xff0c;可分為內外軟硬&#xff0c;有形無形的區別。注重于外&#xff0c;修煉筋骨皮肉的是有形的功夫&#xff1b;注重于…

[已解決]Vistual Stdio 2015 installer Bootstrapper Packages 路徑

VS2015 installer 的預裝包的地址變更成 C:\Program Files (x86)\Microsoft Visual Studio 14.0\SDK\Bootstrapper\Packages 參看文檔&#xff1a;https://msdn.microsoft.com/en-us/library/ms165429(vvs.140).aspx 之前的版本是在 C:\Program Files (x86)\Microsoft SDKs\Win…

java怎樣寫入五個人的成績_用java輸入5個學員姓名和分數,顯示分數最高的學員姓名和分數?...

展開全部import java.util.Scanner;public class Student {private String stuname "";private float stuscore 0;public String getStuname() {e69da5e6ba9062616964757a686964616f31333335316633return stuname;}public void setStuname(String stuname) {this.s…

eBay宣布發布全新的購買和銷售APIs

eBay最近宣布發布兩款全新的購買和銷售APIs。這些APIs旨在促進eBay產品在第三方應用程序中的更好集成。eBay于10月19日在他們的博客上發表了幾篇文章&#xff0c;不僅詳細介紹了這些全新的購買和銷售APIs提供的功能&#xff0c;而且還詳細地總結了他們公司從SOAP&#xff08;簡…

iOS 10 升級后無法真機測試 Could not find Developer Disk Image

&#xff0d;&#xff0d;&#xff0d;2016年9月20日更新 iOS 升級到10之后&#xff0c;你會發現無法進行真機測試了。這種情況我在iOS 8.4 、9.3更新的時候也遇到過。原因是Xcode 的DeviceSupport里面缺少了iOS 10的SDK。所以你可以選擇將Xcode更新到最新版本就可以了&#xf…

java虛擬機參數優化_JAVA虛擬機JVM參數優化(2):垃圾收集算法選擇

JAVA虛擬機JVM優化重要性&#xff0c;昨天JAVA虛擬機JVM參數優化(1)文章中已經描述&#xff0c;今天我們來討論JAVA虛擬機在不同性能要求下如何選擇三種垃圾收集算法。JVM內部結構如下圖所示&#xff1a;串行收集用于單個線程執行垃圾收集的情況&#xff0c;在這種情況下相對它…

Dubbo與Zookeeper、SpringMVC整合和使用(負載均衡、容錯)

2019獨角獸企業重金招聘Python工程師標準>>> 互聯網的發展&#xff0c;網站應用的規模不斷擴大&#xff0c;常規的垂直應用架構已無法應對&#xff0c;分布式服務架構以及流動計算架構勢在必行&#xff0c;Dubbo是一個分布式服務框架&#xff0c;在這種情況下誕生的…

java clicked_關于java:JComponents在調用mouseClicked()之后消失

我正在用Swing編寫Java GUI程序。該界面如下所示&#xff1a;當用戶單擊右側的圖片之一時&#xff0c;我希望它的一個小的預覽顯示在左上角的橙色區域中。我通過SwingWorker線程從計算機上的目錄中提取所有圖像文件。在SwingWorker的done()方法中&#xff0c;我向每個對象添加了…

vim簡單命令教程-firstblood

你想以最快的速度學習人類史上最好的文本編輯器VIM嗎&#xff1f;你先得懂得如何在VIM幸存下來&#xff0c;然后一點一點地學習各種戲法。 Vim the Six Billion Dollar editor Better, Stronger, Faster. 學習 vim 并且其會成為你最后一個使用的文本編輯器。沒有比這個更好的文…

第三課、Qt的誕生和本質------------------狄泰軟件學院

一、GUI用戶界面元素 &#xff08;1&#xff09;、GUI應用程序是由固定的窗口元素所構成 &#xff08;2&#xff09;、操作系統提供了創建用戶界面元素所需要的函數 &#xff08;3&#xff09;、各自功能不同的函數依次調用&#xff0c;從而創建出界面元素 &#xff08;4&#…

java mapstring_ object 遍歷_ListMapString,Object使用Java代碼遍歷以獲取String,Object的值...

List>的結果集怎么使用Java代碼遍歷以獲取String&#xff0c;Object的值&#xff1f;package excel;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class List1{public static void main(String[] args){Map map…

Linux tar命令高級用法——備份數據

Linux tar命令高級用法——備份數據 2015-12-31 Linux學習Linux上有功能強大的tar命令&#xff0c;tar最初是為了制作磁帶備份&#xff08;tape archive&#xff09;而設計的&#xff0c;它的作用是把文件和目錄備份到磁帶中&#xff0c;然后從磁帶中提取或恢復文件。現在我們可…

iOS uiviewcontroller 添加另外一個controller的View

需要 添加 [self addChildViewController:vc]; [_mainScrollView addSubview:vc.view];轉載于:https://www.cnblogs.com/foolish-guo/p/6385288.html

mysql 即學a又學b_MySQL學習第一天

一、 數據庫:*學習重點:創建數據庫/向表添加記錄/查詢記錄數據庫概念:文件系統(存儲和管理)數據庫軟件介紹:Oracle/MySQL/SQL server…分類:關系型數據庫:關系模型組織數據非關系型數據庫:鍵值對關系存儲二、 mysql數據的存儲方式:一臺數據庫服務器中會創建很多個數據庫(一個項…