一、公式
线程数 = CPU核数 * CPU利用率 * (1 + W/C)
即:
线程数 = CPU核数 * CPU利用率 * (计算时间 + 等待时间)/ 计算时间
线程数 = CPU核数 * CPU利用率 * (1 + 等待时间 / 计算时间)
二、出处
这个公式的出处是由 Brian Goetz 在他的著作《Java Concurrency in Practice》中提出的。
中文书《Java 并发编程实践》
Brian Goetz 是一位著名的 Java 技术专家,他的这本书被广泛认为是 Java 并发编程领域的经典之作。这个公式在书中被用来估算线程池的最佳大小。
具体来说,这个公式出现在书的第 8.2 节 “Sizing Thread Pools”(调整线程池大小)中。Goetz 在这里讨论了如何根据系统的特性和任务的性质来确定合适的线程池大小。
虽然这个公式提供了一个很好的理论基础,但 Goetz 也强调,实际应用中还需要考虑具体的场景和进行实际的性能测试来找到最优的线程数。
三、公式介绍
这个公式是用来估算最佳线程数的一种方法,通常被称为"线程数计算公式"或"最优线程数计算公式"。让我们来解析一下这个公式:
线程数 = CPU核数 * CPU利用率 * (1 + 等待时间/计算时间)
其中:
- CPU核数:物理CPU核心的数量
- CPU利用率:通常在0.8-0.9之间,表示CPU的期望利用率
- 等待时间(W):线程等待时间,如I/O操作时间
- 计算时间(C):线程实际运行计算的时间
这个公式考虑了以下因素:
-
CPU核数:更多的核心可以支持更多的并发线程。
-
CPU利用率:考虑到系统开销,通常不会将CPU利用到100%。
-
等待时间与计算时间的比率(W/C):
- 如果程序是计算密集型(W/C接近0),那么线程数约等于CPU核数。
- 如果程序是I/O密集型(W/C较大),则可以设置更多的线程数。
使用这个公式可以帮助开发者估算出一个合理的线程数,以充分利用系统资源,同时避免过多的线程造成的上下文切换开销。但需要注意,这只是一个理论估算,实际的最佳线程数还需要根据具体应用场景和性能测试来确定。
四、示例
4.1 计算密集型
假设我们有一个计算密集型的任务,需要在一个具有8个CPU核心的系统上运行。对于计算密集型任务,等待时间(W)几乎为0,因为CPU大部分时间都在进行计算,而不是等待I/O操作。我们希望CPU的利用率接近100%,即CPU利用率为1。
将这些值代入公式中:
线程数 = CPU核数 * CPU利用率 * (1 + W/C)
由于W(等待时间)几乎为0,W/C也接近0,所以公式可以简化为:
线程数 = CPU核数 * CPU利用率
如果我们希望CPU利用率为100%,即CPU利用率为1,那么:
线程数 = 8 * 1 = 8
这就是为啥网上总说计算密集任务建议设置的线程数为:CPU核数*1的原因
4.2 I/O密集型
假设我们有一个I/O密集型的任务,需要在一个具有4个CPU核心的系统上运行。对于I/O密集型任务,等待时间(W)远大于计算时间©,因为CPU大部分时间都在等待I/O操作完成,而不是进行计算。我们希望CPU的利用率接近100%,即CPU利用率为1。
假设等待时间是计算时间的1倍,即W/C = 1。
将这些值代入公式中:
线程数 = CPU核数 * CPU利用率 * (1 + W/C)
线程数 = 4 * 1 * (1 + 1)
线程数 = 4 * (1 + 1) = 4 * 2 = 8
这就是为啥网上总说IO密集任务建议设置的线程数为:CPU核数*2的原因