深刻理解-CPU核心数与线程池并发线程数关系

那是一个风和日丽的下午!java

面试官微微一笑,对我说:“小伙子,合理配置线程池你是如何考虑的?面试

我微微一笑,说出了个人答案:算法

首先确认业务是CPU密集型仍是IO密集型的,数据库

若是是CPU密集型的,那么就应该尽可能少的线程数量,通常为CPU的核数+1;编程

若是是IO密集型:因此可多分配一点 cpu核数*2 也可使用公式:CPU 核数 / (1 - 阻塞系数);其中阻塞系数在 0.8 ~ 0.9 之间。服务器

面试官心想,有点东西,接着追问:“那你是如何获得的这个公式,或者说你是如何根据CPU核心数肯定线程池并发线程数的网络

我心想这不是小瞧我嘛?不屑回答的我脱下了个人帽子并发

哈哈哈哈,进入正题!测试


1,追书溯源

关于如何计算并发的线程数量,通常分两派,来自两本书,且都是好书,线程

第一派:《Java Concurrency in Practice》即《java并发编程实践》,咱们简称A派。

第二派:《Programming Concurrency on the JVM Mastering》即《Java 虚拟机并发编程》,咱们简称B派。

到底哪一个是对的?咱们截取书中部份内容具体看看。

A派一书中是这样写的

B派一书中是这样写的

2,大胆分析

对于A派,假设CPU跑满,即撇开CPU使用率这个因素,A派认为 线程数 = Ncpu * ( 1 + w/c )

大胆假设将B派的公式等于A派公式,

Ncpu / (1-阻塞系数) = Ncpu * ( 1 + w/c )阻塞系数 = 阻塞时间 /(阻塞时间+计算时间)

这个结论在派系二后续中获得应征,以下图:

\color{red}{因此得出一个结论:A派和B派实际上是一个公式!}

3,实际运用

那么实际使用中并发线程数如何设置呢?分析以下(咱们以A派公式为例):

Nthreads = Ncpu * (1+w/c)

IO密集型:通常状况下,若是存在IO,那么确定w/c>1(阻塞耗时通常都是计算耗时的不少倍),可是须要考虑系统内存有限(每开启一个线程都须要内存空间),这里须要上服务器测试具体多少个线程数适合(CPU占比、线程数、总耗时、内存消耗)。

若是不想去测试,保守点取1即,Nthreads=Ncpu*(1+1)=2Ncpu。这样设置通常都OK。

CPU密集型: 假设没有等待w=0,则W/C=0. Nthreads=Ncpu。

再次概括下:

IO密集型 = 2Ncpu(能够测试后本身控制大小,2Ncpu通常没问题)(常出现于线程中:数据库数据交互、文件上传下载、网络数据传输等等)

CPU密集型 = Ncpu(常出现于线程中:复杂算法)

java中:Ncpu = Runtime.getRuntime().availableProcessors()

4,继续研究

A派的另外一个说法

即对于计算密集型的任务,在拥有N个处理器的系统上,当线程池的大小为N+1时,一般能实现最优的效率。(即便当计算密集型的线程偶尔因为缺失故障或者其余缘由而暂停时,这个额外的线程也能确保CPU的时钟周期不会被浪费。)

即,计算密集型=Ncpu+1,可是这种作法致使的多一个cpu上下文切换是否值得,这里不考虑。读者可本身考量。


本文借鉴概括:Flag Counter 《根据CPU核心数肯定线程池并发线程数》

相关文章
相关标签/搜索