高并发下,怎么选择最优的线程数?

最常见的说法应该是,采用线程池,他可以有效降低线程创建释放的时间花销及资源开销,如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及“过度切换”(在JVM中采用的处理机制为时间片轮转,减少了线程间的相互切换) 。
下面是获得cou数目的方法。

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

最好的线程数计算方法:

Ncpu = CPU的数量
Ucpu = 目标CPU的使用率, 0 <= Ucpu <= 1,一般极端情况下设为1
W/C = 等待时间与计算时间的比率
为保持处理器达到期望的使用率,最优的池的大小等于:
Nthreads = Ncpu x Ucpu x (1 + W/C)

为了正确地设置线程池的长度,你必须估算出任务花在等待的时间与用来计算的时间的比率(cpu利用率);这个估算值不必十分精确,而且可以通过一些监控工具获得。在控制变量法的作用下,使用visualvm一般可以做到估算。(这是对于包含了 I/O和其他阻塞操作的任务,不是所有的线程都会在所有的时间被调度,因此你需要一个更大的池。)
不过,对于计算密集型的任务,一个有Ncpu个处理器的系统通常通过使用一个Ncpu + 1个线程的线程池来获得最优的利用率(计算密集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好**有一个“额外”的线程,**可以确保在这种情况下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。再加个1。
根据短板效应,真实的系统吞吐量并不能单纯根据CPU来计算。那要提高系统吞吐量,就需要从“系统短板”(比如网络延迟、IO)着手:
尽量提高短板操作的并行化比率,比如多线程下载技术;
增强短板能力,比如用NIO替代IO;
第一条可以联系到Amdahl定律,正好计算机体系结构上过这门课,这条定律定义了串行系统并行化后的加速比计算公式:加速比 = 优化前系统耗时 / 优化后系统耗时 加速比越大,表明系统并行化的优化效果越好。Addahl定律还给出了系统并行度、CPU数目和加速比的关系,加速比为Speedup,系统串行化比率(指串行执行代码所占比率)为F,CPU数目为N:Speedup <= 1 / (F + (1-F)/N)
当N足够大时,串行化比率F越小,加速比Speedup越大。
我想最终结论最好为:
IO密集型 = 2Ncpu(可以测试后自己控制大小,2Ncpu一般没问题)(常出现于线程中:数据库数据交互、文件上传下载、网络数据传输等等)
计算密集型 = Ncpu+1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值