I/ O 密集型业务,线程数量要设置成 CPU 的 2 倍!
也不晓得这是哪本书的坑爹实践,当初总有一些小青年老拿着这样的定理来说教。说的山盟海誓,毋庸置疑,好像是权威的化身。探讨时把这样的实践当作前提,真的是受益不浅。
但惋惜的是,这样的实践站不住脚。我只须要一个简略的反诘,它就不攻自破:
Tomcat 的默认线程数是多少呢?
它既不是 CPU 的 2 倍,也不是什么其余数值。在某些高并发的服务中,它的外围线程数,可能达到数千甚至上万。对于一个 Tomcat 来说,它解决的大多数都是 I / O 密集型的业务,能够说是最好的实际场景。
要明确这个线程数设置的玄机,就必须理解 I / O 申请的特点。I/ O 申请不仅仅指的是磁盘读写,在互联网服务中更多指的是网络 I / O 申请。
I/ O 申请的速度,要远低于 CPU 运行的速度。大部分 I / O 申请,在发动之后,就进入期待状态,这个期待状态不会节约 CPU,所以一台机器在同一时刻反对的 I / O 申请,能够很多。
如果 I / O 申请的速度比拟快,和 CPU 的耗时对等的时候,咱们把解决 I / O 的线程数,设置成 CPU 的 2 倍,是正当的。但事实中并没有这么多如果,咱们要解决秒成千上万的 I / O 申请,注定了它的耗时要比 CPU 多的多。
像 RPC 组件,比方 Dubbo 服务端,也会设置一个比拟大的线程数(比方 600);Feign 这种就更不必多说了,短连贯意味着更多线程数的反对。这都是些最佳实际。
尽管 I / O 线程数量增多,会造成十分频繁的上下文切换,进而影响效率。但在互联网利用中,它却是一个优良的解决方案。
更优良的解决形式也有,那就是应用协程。协程是用户态的线程,是对一般线程更细粒度的划分。它是在用户态运行的,由用户自行调度,所以也就防止了频繁的上下文切换问题。
但协程在 Java 中还不成熟,它仍然是 Golang 语言的迷人个性。应用 Golang 开发的 Web 服务,能够采纳更少的线程来反对大量 I / O 密集型的申请。
综上所述,题目的表述并不正确,而且错的离谱。