线程池的大小是如何确定的?
每个使用到线程池的同学,在面试中都不免会被问到这个问题,如果有同学学习过牛客的Linux高并发服务器开发,那么他的答案可能是:“线程池大小与CPU的核心数相关,一般有几个核心就创建几个线程”,这个回答不能说是错误的,但是却不够全面,或者说还不够,没有触及线程池大小确定的核心原因。
Number of threads = Number of Available Cores * (1 + Wait time / Service time)
- 如果你带着疑问去谷歌搜索,你会看见上面这个式子,这个式子是Brian Goetz在他那本著名的《Java Concurrency in Practice》给出的,其中
- Waiting time : 是CPU等待IO绑定任务完成所花费的时间。在我们的项目中代表等待来自远程服务的HTTP响应等的时间。
- Service time :是CPU真正处理任务所花费的时间。在我们的任务中,代表处理HTTP响应,处理内存映射等任务的时间
- 这两个时间的比值,被称为“阻塞系数”
- 通过这个公式,我们似乎已经找到了确定线程池大小的真正因素:CPU的核心数、待处理任务的I/O时间与CPU计算时间,这样你在面试时就能自信地对面试官说:“线程池的大小是根据CPU的核心数和所需要处理的任务的阻塞系数来决定的,其中阻塞系数是任务的等待时间和CPU处理时间的比值,阻塞系数越接近0,代表任务越表现为计算密集型任务,如果用公式来表达地话,线程池大小等于可用的CPU数乘以一加上任务等待时间除以CPU计算时间。”
Little’s Law
为了更好地去解释线程池大小确定原因,我们需要一个法则:Little’s Law,中文为利特尔法则,其内容为:在一个稳定地系统中,长期地平均顾客人数(L),等于长期的有效抵达率(λ),乘以顾客在这个系统中平均的等待时间(W),用公式来表达这个关系如下:
$$ L = λW $$
看到这里,你可能会有点疑惑,这个法则怎么就和线程池的大小相联系来了呢?这其实只是描述问题,代入到我们的服务器项目中:
- L 就是我们的服务器需要同时处理的请求数量
- λ 就是请求到达的速度
- W 就是我们处理单个请求需要花费的时间。
很显然当线程池的大小刚好等于L时,线程池的大小达到最佳,也即每个到达的任务都会被立马处理,而不会囤积在等待队列中延迟处理。
线程池大小的实际计算方法
TODO
WebServer项目中怎么动态调整线程池的大小?
TODO
#我的秋招日记#
