# 程序开多少线程合适

# 为什么要找最佳线程数

1. 过多的线程只会造成,更多的内存开销,更多的 CPU 开销,但是对提升 QPS 确毫无帮助

2. 使用多线程就是在正确的场景下通过设置正确个数的线程来充分的利用 CPU 和 I/O 最大化程序的运行速度。

# 从两个方面和分析:

  • CPU 密集型程序

  • I/O 密集型程序

  1. CPU 密集型程序,一个完整请求,I/O 操作可以在很短时间内完成,CPU 还有很多运算要处理,也就是说 CPU 计算的比例占很大一部分,线程等待时间接近 0
    1. 单核 CPU: 一个完整请求,I/O 操作可以在很短时间内完成, CPU 还有很多运算要处理,也就是说 CPU 计算的比例占很大一部分,线程等待时间接近 0。单核 CPU 处理 CPU 密集型程序,这种情况并不太适合使用多线程。
    2. 多核 : 如果是多核 CPU 处理 CPU 密集型程序,我们完全可以最大化的利用 CPU 核心数,应用并发编程来提高效率。CPU 密集型程序的最佳线程数就是:理论上线程数量 = CPU 核数(逻辑),但是实际上,数量一般会设置为 CPU 核数(逻辑)+ 1(经验值), 计算 (CPU) 密集型的线程恰好在某时因为发生一个页错误或者因其他原因而暂停,刚好有一个 “额外” 的线程,可以确保在这种情况下 CPU 周期不会中断工作
  2. I/O 密集型程序,与 CPU 密集型程序相对,一个完整请求,CPU 运算操作完成之后还有很多 I/O 操作要做,也就是说 I/O 操作占比很大部分,在进行 I/O 操作时,CPU 是空闲状态,所以我们要最大化的利用 CPU,不能让其是空闲状态,由于 I/O 等待时间较长,线程等待时间所占比例越高,需要越多线程;线程 CPU 时间所占比例越高,需要越少线程,
    1. I/O 密集型程序的最佳线程数就是: 最佳线程数 = CPU 核心数 * (1/CPU 利用率) = CPU 核心数 *(1 + (I/O 耗时 / CPU 耗时))
    2. 如果几乎全是 I/O 耗时,那么 CPU 耗时就无限趋近于 0,所以纯理论你就可以说是 2N(N=CPU 核数),当然也有说 2N + 1 的,1 应该是 backup
    3. 一般我们说 2N + 1 就即可

# 拓展

1、我们已经知道创建多少个线程合适了,为什么还要搞一个线程池出来?

  • 风险不受控
  • 频繁创建开销大

# 风险不受控

系统资源有限,每个人针对不同业务都可以手动创建线程,并且创建标准不一样(比如线程没有名字)。当系统运行起来,所有线程都在疯狂抢占资源,内存被无情榨干耗尽,这好比一个正木马程序(出现问题,自然也就不可能轻易的发现和解决)。

# 频繁创建开销大

内存分配,对象初始化,线程创建,线程状态保存等均需要资源