如何合理地估算线程池大小?

如何合理地估算线程池大小?服务器

这个问题虽然看起来很小,却并不那么容易回答。你们若是有更好的方法欢迎赐教,先来一个天真的估算方法:假设要求一个系统的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、内存、硬盘读写速度、网络情况等)来不断尝试达到一个符合实际的合理估算值。

相关文章
相关标签/搜索