创建多少个线程合适?

创建多少个线程合适?

拾人牙慧,看了一篇博客做做记录。

大佬博客:https://www.jianshu.com/p/f30ee2346f9f

1.为什么要使用多线程?

相比单线程优势在同时处理多个事件,速度快的时间优势;但多线程也同样容易出问题。

合适的场景+合适的线程个数=运行速度

CPU密集型程序

一个完整的请求,I/O操作可以在很短的时间内完成,CPU还有很多运算要处理,也就是说CPU计算的比例占很大一部分

**单核CPU:**即使开4个线程也同样和单线程的执行时间一样,由于单核,一个线程执行时其他线程在等待CPU时间片,但是4个线程还有线程上下文切换的问题。

**四核CPU:**这样就没有了线程间切换等待CPU时间片的问题了,四个线程同时进行,理论上效率提升了4倍。

所以,如果是多核CPU处理CPU密集型程序,完全可以最大化利用CPU核心数,应用并发编程来提高效率。

I/O密集型程序

与CPU密集型程序相对,一个完整请求,CPU运算操作完成之后还有很多I/O操作要做,也就是说I/O操作占比很大。
在这里插入图片描述

这里原本是打算偷原博主的图的感觉有图更容易理解,后来找到了还算好用的画图工具就自己对比原博主的CPU耗时:I/O耗时=1:2的画了个1:3的。

从上图可以发现如果把CPU和I/O的耗时变成1:4则会产生CPU的空闲,这时设置成5个线程就又可以最大化利用cpu了。

2.创建多少个线程合适?

上面对CPU密集型和I/O密集型两种情况作了简单介绍,下面分析下这两种场景需要的线程数

CPU密集型程序创建多少个线程合适?

理论上 线程数量=CPU核心数就可以了,但是实际上,一般会设置CPU核心数+1的值

计算(CPU)密集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好有一个“额外”的线程,可以确保在这种情况下CPU周期不会中断工作。

所以对于CPU密集型程序,CPU核心数+1个线程数是比较的值。

I/O密集型程序创建多少个线程合适?

最 佳 线 程 数 = 1 C P U 利 用 率 = 1 + ( I / O 耗 时 C P U 耗 时 ) 最佳线程数=\frac{1}{CPU利用率}=1+\left(\frac{I/O耗时}{CPU耗时}\right) 线=CPU1=1+(CPUI/O)

假设:CPU耗时 = 2;

​ I/O耗时 = 4;
最 佳 线 程 数 : 1 + ( 4 2 ) = 3 最佳线程数:1+\left(\frac{4}{2}\right)=3 线1+(24)=3
这是单核心下的最佳线程数,如果是多核心,那么最佳线程数的公式就是:
最 佳 线 程 数 = C P U 核 心 数 × ( 1 C P U 利 用 率 ) = C P U 核 心 数 × [ 1 + ( I / O 耗 时 C P U 耗 时 ) ] 最佳线程数=CPU核心数×\left(\frac{1}{CPU利用率}\right)=CPU核心数×\left[1+\left(\frac{I/O耗时}{CPU耗时}\right)\right] 线=CPU×(CPU1)=CPU×[1+(CPUI/O)]
实际上我们一般不知道确切的CPU利用率,所以估算个大概。

如果几乎全是I/O耗时,那理论值就是CPU核心数×2 的线程数

这里是我所看的那篇博客的原话,但是我感觉不对,如果几乎全是I/O耗时CPU繁忙占比会趋近于0,按照以上公式则会趋近于无穷,所以这种情况下这个公式是不适用的。因为线程不能无限开,每开辟一个线程就会占用一定的资源,所以这种情况下就设定为几倍CPU核心数的固定值,例如6×CPU核心数。

这些只是理论值,不过在初期阶段,我们可以按照这个理论作为伪标准,毕竟差也不会差太多。

有很多工具帮助我们得到CPU利用率这些值,如SkyWalking,CAT,ZipKin

3.例题:

第一题:

假设要求一个系统的TPS至少为20,然后假设每个Transaction由一个线程完成,继续假设平均每个线程处理一个Transaction的时间为4s

一个线程1s的处理能力为 1 s 4 s = 1 4 \frac {1s} {4s}=\frac{1}{4} 4s1s=41个TPS

那么要求至少为20个TPS,则理论线程数=20÷ 1 4 \frac{1}{4} 41=80(个)

但是这里没有考虑CPU核心数的问题,80核CPU不太现实,这样会有上下文切换的问题,2020年3月高性能计算公司Ampere发布了业内第一款80核ARM架构64位处理器Altra,所以一般服务器也就16核32核左右,这就需要去做平衡调优了。

第二题:

计算操作需要5ms,DB操作需要100ms,对于一个8核CPU的服务器来说怎么设置线程数?

线 程 数 = 8 × ( 1 + 100 5 ) = 168 ( 个 ) 线程数=8×\left(1+\frac{100}{5}\right)=168(个) 线=8×(1+5100)=168()

那如果DB的QPS上限是1000,此时这个线程又该设置多大呢?

1s=1000ms 一个TPS105ms

一个线程每秒可以处理的任务数就是 1000 105 \frac{1000}{105} 1051000

那么168个线程每秒可以出来的任务数为168× 1000 105 \frac{1000}{105} 1051000=1600

又因为DB的QPS上限为1000,所以线程数要等比例减少 168× 1000 1600 \frac {1000}{1600} 16001000 = 105

同样这里没有考虑CPU核心数的问题。

增加CPU核心数就一定能解决问题么?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lcwn9WEi-1595397109645)(C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20200722133805887.png)]

S = 1 1 − p + ( p n ) S=\frac{1}{1-p+\left(\frac pn\right)} S=1p+(np)1
假设下

​ n趋于无穷

​ p=5%


S = 1 1 − 0.05 + ( 0.05 ∞ ) S=\frac{1}{1-0.05+\left(\frac {0.05}{∞}\right)} S=10.05+(0.05)1

​ S的就无限趋于20

这里就是串行百分比决定了性能的提升能力,CPU核心数多并不一定能带来多少效率的提升,到达一定数目之后核心数增加带来的收益会越来越小。

总结,CPU繁忙时间占比越高,设置的线程数越少,CPU繁忙时间占比越低,设置的线程数越多(但资源有限),线程数和CPU繁忙时间呈大致的反比关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值