如何合理配置线程池的大小

zszdevelop大约 3 分钟

如何合理配置线程池的大小

1. 理论背景

一般需要根据任务的类型来配置线程池大小:

  • 如果是CPU密集型任务,就需要尽量压榨CPU,应配置尽可能小的线程,参考值可以设为 NCPU+1

  • 如果是IO密集型任务,因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,参考值可以设置为2NCPU+1

当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。

2. 什么是io秘籍和CPU 秘籍

  • io密集型(要减少请求数量或请求大小)

    1. 数据库操作
    2. 网络请求操作
  • cpu 密集型

    1. 程序计算

3. 实例测试

在做数据清理时,需要查询数据库,做数据清洗完成后,再保存到数据库

测试逻辑步骤

  1. 查询出总记录数
  2. 每100条记录划分一组在线程池中操作

我win 核心线程为4

不使用多线程的时候,每分钟执行500条

改用多线程后

线程数每分钟执行条数5分钟执行条数
核心线程数5,最大线程数104400(初次线程停顿条数1100)
核心线程数10,最大线程数208400(初次线程停顿条数2100)
核心线程数20,最大线程数4012300(初次线程停顿条数4100)
核心线程数30,最大线程数6018300(初次线程停顿条数6100)
核心线程数40,最大线程数8024300(初次线程停顿条数8100)
核心线程数50,最大线程数10026716(初次线程停顿条数9994)
核心线程数60,最大线程数12027300(初次线程停顿条数9854)
核心线程数70,最大线程数14019942(初次线程停顿条数9747)
核心线程数80,最大线程数16029770(初次线程停顿条数9747)

初次线程停顿条数:清理到数据库中的数据从0开始到一个稳定的数(线程池差不多同一时间执行完毕的,过渡到其他线程)

该实验建立在每分钟的基础上。每个线程执行时间15-20s左右。那1分钟执行3-4次。所以误差比较明显

3.1 实验分析

实现出的结果显示2n+1 的结论。线程数量还远不能达到最佳线程。继续查阅资料发现一个估算公式

最佳线程数目 = ((线程等待时间+线程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,所以决定一个系统吞吐量上限的是 CPU。增强 CPU 处理能力,可以提高系统吞吐量上限。但根据短板效应,真实的系统吞吐量并不能单纯根据 CPU 来计算。那要提高系统吞吐量,就需要从 “系统短板”(比如网络延迟、IO)着手:

  • 尽量提高短板操作的并行化比率,比如多线程下载技术
  • 增强短板能力,比如用 NIO 替代 IO

代码测算

合理估算java的线程池大小及队列数open in new window

参考文章

如何合理地估算线程池大小?open in new window

Loading...