如何合理地估算线程池大小?服务器
这个问题虽然看起来很小,却并不那么容易回答。你们若是有更好的方法欢迎赐教,先来一个天真的估算方法:假设要求一个系统的TPS(Transaction Per Second或者Task Per Second)至少为20,而后假设每一个Transaction由一个线程完成,继续假设平均每一个线程处理一个Transaction的时间为4s。那么问题转化为:网络
如何设计线程池大小,使得能够在1s内处理完20个Transaction?多线程
计算过程很简单,每一个线程的处理能力为0.25TPS,那么要达到20TPS,显然须要20/0.25=80个线程。性能
很显然这个估算方法很天真,由于它没有考虑到CPU数目。通常服务器的CPU核数为16或者32,若是有80个线程,那么确定会带来太多没必要要的线程上下文切换开销。测试
再来第二种简单的但不知是否可行的方法(N为CPU总核数):优化
若是是CPU密集型应用,则线程池大小设置为N+1spa
若是是IO密集型应用,则线程池大小设置为2N+1线程
若是一台服务器上只部署这一个应用而且只有这一个线程池,那么这种估算或许合理,具体还需自行测试验证。设计
接下来在这个文档:服务器性能IO优化 中发现一个估算公式:code
1.最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
好比平均每一个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,好比IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算获得:((0.5+1.5)/0.5)*8=32。这个公式进一步转化为:
2.最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
能够得出一个结论:线程等待时间所占比例越高,须要越多线程。线程CPU时间所占比例越高,须要越少线程。
上一种估算方法也和这个结论相合。
一个系统最快的部分是CPU,因此决定一个系统吞吐量上限的是CPU。加强CPU处理能力,能够提升系统吞吐量上限。但根据短板效应,真实的系统吞吐量并不能单纯根据CPU来计算。那要提升系统吞吐量,就须要从“系统短板”(好比网络延迟、IO)着手:
尽可能提升短板操做的并行化比率,好比多线程下载技术
加强短板能力,好比用NIO替代IO
第一条能够联系到Amdahl定律,这条定律定义了串行系统并行化后的加速比计算公式:
1.加速比=优化前系统耗时 / 优化后系统耗时
加速比越大,代表系统并行化的优化效果越好。Addahl定律还给出了系统并行度、CPU数目和加速比的关系,加速比为Speedup,系统串行化比率(指串行执行代码所占比率)为F,CPU数目为N:
Speedup <=
1
/ (F + (
1
-F)/N)
当N足够大时,串行化比率F越小,加速比Speedup越大。
写到这里,我忽然冒出一个问题。
是否使用线程池就必定比使用单线程高效呢?
答案是否认的,好比Redis就是单线程的,但它却很是高效,基本操做都能达到十万量级/s。从线程这个角度来看,部分缘由在于:
1.多线程带来线程上下文切换开销,单线程就没有这种开销
2.锁
固然“Redis很快”更本质的缘由在于:Redis基本都是内存操做,这种状况下单线程能够很高效地利用CPU。而多线程适用场景通常是:存在至关比例的IO和网络操做。
因此即便有上面的简单估算方法,也许看似合理,但实际上也未必合理,都须要结合系统真实状况(好比是IO密集型或者是CPU密集型或者是纯内存操做)和硬件环境(CPU、内存、硬盘读写速度、网络情况等)来不断尝试达到一个符合实际的合理估算值。