首先,需要考虑到线程池所进行的工作的性质:
- IO密集型
- CPU密集型
简单的分析来看,如果是CPU密集型的任务,我们应该设置数目较小的线程数,比如CPU数目 加1。如果是IO密集型的任务,则应该设置可能多的线程数,由于IO操作不占用CPU,所以, 不能让CPU闲下来。当然,如果线程数目太多,那么线程切换所带来的开销又会对系统的响 应时间带来影响。
在《linux多线程服务器端编程》中有一个思路,CPU计算和IO的阻抗匹配原则。
如果线程池中的线程在执行任务时,密集计算所占的时间比重为P(0<P<=1),而系统一共有C
个CPU,为了让CPU跑满而又不过载,线程池的大小经验公式 T = C / P
。在此,T 只是一
个参考,考虑到 P 的估计并不是很准确,T 的最佳估值可以上下浮动 50%。
这个经验公式的原理很简单,T 个线程,每个线程占用 P 的 CPU 时间,如果刚好占满 C 个 CPU, 那么必有
T * P = C
下面验证一下边界条件的正确性:
假设C = 8,P = 1.0,线程池的任务完全是密集计算,那么 T = 8。只要8个活动线程就能让 8个CPU饱和,再多也没用了,因为CPU资源已经耗光了。
假设C = 8,P = 0.5,线程池的任务有一半是计算,有一半在等IO上,那么T = 16.考虑操 作系统能灵活,合理调度 sleeping/writing/running 线程,那么大概 16 个 “50%繁忙的 线程”能让 8 个 CPU 忙个不停。启动更多的线程并不能提高吞吐量,反而因为增加上下文 切换的开销而降低性能。
如果 P < 0.2,这个公式就不适用了,T 可以取一个固定值,比如 5*C。另外公式里的 C 不一定是 CPU 总数,可以是“分配给这项任务的 CPU 数目”,比如在8核机器上分出4个核来 做一项任务,那么 C=4
文章如何合理设置线程池大小里面提到了一个公式:
最佳线程数目 = ((线程等待时间 + 线程CPU时间) / 线程CPU时间 )* CPU数目
比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为 1.5s,
CPU 核心数为 8,那么根据上面这个公式估算得到: ((0.5+1.5)/0.5)*8=32
。这个公式进
一步转化为:
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
可以得出一个结论:
线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
以上公式与之前的CPU和IO密集型任务设置线程数基本吻合。