设置线程池的大小并不需要像数学公式一样严谨,只需要避开”过大“、”过小“即可。如果线程池线程数量设置过大,大量的线程去争夺非常有限的的CPU和内存资源,只会消耗更高的内存和增加上下文切换。但是如果线程池线程数量设置过小,CPU的空闲时间过长,降低了吞吐,就失去了我们使用多线程的意义。

如果想要设置线程池的理想大小,我们需要从系统资源和任务特性来进行考虑:

  • 系统有多少CPU、内存大小
  • 任务是计算密集型、I/O密集型还是混合类型
  • 是否依赖于稀缺资源

  1. 对于计算密集型的任务,在执行任务时,线程会一直执行不会出现等待,所以在拥有NCPU的配置时,线程池设置为N+1,通常能够实现最优的利用率。

为什么是N+1不是N
当线程偶尔由于页缺失故障或者其他原因而暂停时,这个替补线程能保证CPU的时钟周期不被浪费。但是这种做法导致的多一个CPU上下文切换是否值得,这里不考虑。

  1. 对于I/O密集型和混合类型的任务,在执行任务时,由于存在I/O操作或者其他阻塞操作,线程不会一直处于执行状态,因此这种情况下的线程数应适当放大。为了确保线程数相对精确,我们通常需要估算出任务的等待时间和计算时间的比值,通过下面的公式确定线程数。
/**
 * N : CPU数量
 * U : 预期的CPU利用率,通常为1
 * W : 等待时间
 * C : 计算时间
 */

线程数 = N * U * ( 1 + W / C )


需要注意的是,上面讨论的两种情况中并没有考虑到稀缺资源的问题,这是由于稀缺资源对线程池的约束条件计算起来相对简单,计算每个任务对该资源的需求量,然后用总量除以每个任务的需求量,得到的就是线程池大小的上限了。

Q.E.D.


Stay focused and work hard!