掘金 后端 ( ) • 2024-04-06 15:44

theme: smartblue highlight: a11y-dark

  • 🏃‍♂️ 微信公众号: 朕在debugger
  • © 版权: 本文由【朕在debugger】原创、需要转载请联系博主
  • 📕 如果文章对您有所帮助,欢迎关注、点赞、转发和订阅专栏!

目标

配置好线程池参数,压榨CPU,资本家看了都觉得惭愧!


前言

无论是个人项目或是公司项目,线程池参数配置得好与坏对于项目整体的运行情况都会有很大的影响!

Tips:有一定用户量使用的情况下🐶,如果没人用当我没说

步骤:

Tips:默认读者已经知晓线程池各个常用参数的含义,以及使用过线程池,此篇文章旨在如何设置参数的大小,才能更好的发挥CPU的威力。


一、区分项目是 CPU 密集型任务还是 I/O 密集型任务

CPU 密集型任务:

CPU 密集型任务是指那些主要消耗 CPU 计算能力的任务。这类任务通常需要大量的 CPU 计算资源来完成,而对于 I/O 资源的需求相对较少。

典型的 CPU 密集型任务包括数学计算、图像处理、加密解密、数据压缩等需要大量 CPU 计算的任务。

对于 CPU 密集型任务,最优化的资源利用是通过尽可能多地利用 CPU 运算能力来提高处理速度,因此线程池的配置应该注重于充分利用 CPU 核心,避免过度的线程竞争,提高计算效率。

I/O 密集型任务:

I/O 密集型任务是指那些主要消耗输入/输出操作的任务。这类任务通常需要等待 I/O 操作的完成,而 CPU 计算的需求相对较少。

典型的 I/O 密集型任务包括文件读写、网络通信、数据库操作等需要大量 I/O 操作的任务。

对于 I/O 密集型任务,最优化的资源利用是通过合理的异步处理、线程池的合理配置以及有效的 I/O 操作来减少等待时间,充分利用 CPU 时间处理其他任务。

CPU 密集型任务主要受限于 CPU 计算能力,而 I/O 密集型任务主要受限于 I/O 操作的速度。

在实际应用中,针对不同类型的任务选择合适的资源分配策略和线程池配置方案可以最大程度地提高系统的性能和资源利用效率。

二、网络话术:CPU 密集型就采用 CPU 核数 + 1, I/O 密集型就是 CPU 核数 * 2

线程池的参数是跟据业务以及系统整体负载定义的,并没有绝对公式。

以下三点是必须要考量的!

1、从整体的负载上,判断线程池数量多不多? 2、是否有大批量消耗 CPU 的任务? 3、线程池运行是否需要高实时?

🌴如果项目任务比较单一,线程池数量较少且业务需要更快的响应时间。

那么如果 I/O 密集型任务,核心线程数设置 CPU 核心数 * 5,最大线程数设置核心线程数 * 1.5。 经过测试,这种能更好压榨服务器 CPU。

🌳如果项目任务比较多,线程池定义也比较多,那么就要考虑定义多个线程池以及很多线程之间的 CPU 上下文切换问题。

因为,当你的线程数远远大于 CPU 且都在运行时,线程是拿不到 CPU 调度的。 这个时候,我们就该从全局角度上考虑将线程数调整小一些。

三、举例说明 I/O 密集型任务的线程池配置

1、核心线程数量可以通过如下方法计算得出

private Integer calculateCoreNum() {
        int cpuCoreNum = Runtime.getRuntime().availableProcessors();
        return new BigDecimal(cpuCoreNum).multiply(new BigDecimal("5")).intValue();
}

2、最大线程数量由核心线程数量扩大 1.5 倍即可

int maximumPoolSize = corePoolSize + (corePoolSize >> 1);

其他参数暂不做演示

四、假如项目任务数量很大,该配置顶不住咋搞?

还问呢?上报!升配置啊!没有什么问题是升级配置解决不了的!

假如每秒的任务数量tasksNum范围是500 至 1000,每个任务花费的时间time假设为0.1s,系统允许容忍的最大响应时间ToleranceTime为1s

此时,你的核心线程数量就应该这么计算

coreNum = tasksNum / (1/time) = (500 至 1000) / 10 = 50 至 100

又根据二八定律,如果80%的每秒任务数量小于800,那 coreNum 设置为 80 即可!

那么阻塞队列的容器又该如何计算呢?

BlockingQueueCapacity = coreNum / time * ToleranceTime = 80 / 0.1 * 1 = 800

▲图 / 加油吧,少年!


五、总结

每个项目关于线程池的参数都是不一样的,都是跟据业务以及系统整体负载定义的,只有多尝试,多比较,才能得出最优解!

finally

如果大家觉得本文写得不错,别忘了给个赞哦!同时,如果您有任何疑问或建议,欢迎在评论区留言,让我们一起交流、探讨!