最近跟一个同事聊天时,同事说之前在某 BAT 大厂实习后台开发时,做一个接口如果用多线程,数量都是 4000 个线程起,我对此表示怀疑。因为据我的认知,线程数量一般开到 CPU 核心数最好,最好不要超过 2 倍 CPU 核心数。因此,想请教下给为大佬,实际生产中用到的高并发的情况,真的能开这么多线程吗?
1
Tinet 2018-09-17 14:08:41 +08:00
你确定他说的不是协程
|
2
lirau 2018-09-17 14:19:03 +08:00
|
3
reus 2018-09-17 14:21:32 +08:00
可能说的是集群分配给这个接口的数量吧,单机开这么多没意义。
|
4
dingzs3 2018-09-17 14:24:34 +08:00
这个估计就是不靠谱的,单机如果线程数过多,会产生太多的上下文切换开销和调度的开销,还有就是如果 cpu 迁移导致的缓存失效代价。
|
5
lhy360121 2018-09-17 14:24:40 +08:00
能。
和 cpu 核心数一致的或 2 倍的应该是进程,不是线程。 高配的机器可以开到几百或上千的线程。 还和开发语言和业务场景有过。 |
6
chocotan 2018-09-17 14:31:16 +08:00
看是 cpu 密集还是 io 密集
|
8
lhy360121 2018-09-17 14:36:48 +08:00
|
9
georgetso 2018-09-17 14:43:18 +08:00
|
10
xylophone21 2018-09-17 14:52:51 +08:00
粗略来说,你的认知没错,但有前提。
其前提是(类似) Nginx 中的那种异步模型,这种方式下,一个线程(进程)可以服务多个请求,由于每个线程实际上都很忙,所以超过 CPU 个数太多反而不好,增加上下文切换的消耗。这种方式性能很高,但代码写起来困难,因为相当于你手工处理了操作体统上下文切换的事情,但处理的不那么特化,只适应当前一种场景。 在这种模型出现之前,流行的是多线程 /进程模型,一个线程 /进程为一个连接服务,每个线程大多数时候都在等待 IO,所以开的比 CPU 核心数多的多也没关系,也不得不开。这样的代码写起来非常简单,因为操作系统帮你隔离了每个请求之间的上下文切换,但性能就差一些,因为这种上下文切换很重,很通用,做了超出预期的事。 再进一步,协程又平衡了两种方式,这是题外话。 |
11
dychenyi 2018-09-17 15:14:41 +08:00
都没错。
理解的问题。 你的线程是 cpu 密集型。 他的线程是 IO 密集型。 好比你写个 socket server 端,client 端可以连进来,设计成一个线程处理一个 client。 那么最起码能连几百个 client 端就需要几百个线程了。 |
12
q397064399 2018-09-17 15:16:19 +08:00
当然可以.. 实际上拿线程池抗压 又不是没干过,因为后端大部分时候 都阻塞在网络 IO 数据库网络 IO 等等上面,
其实实际的计算负载很低的.. |
13
catror 2018-09-17 15:16:36 +08:00 via Android
看业务场景来决定
|
14
Allianzcortex 2018-09-17 15:20:45 +08:00
@xylophone21 @lhy360121 @ayonel 我理解的 [线程数量一般开到 CPU 核心数最好,最好不要超过 2 倍 CPU 核心数] 这句话的产生是因为 Intel 可以让一个实体 CPU 模拟出两倍逻辑 CPU...但具体使用场景里线程数量应该没有什么固定的 best pramater,参考 https://www.quora.com/How-can-I-tell-how-many-processes-are-too-many-on-a-Linux-machine 里的回答, [Linux scales very well with the number of processes on a system, Thus there isn't a definitive answer to how many processes are "too many." ] ,所以系统目标是 system load 要小,这个时候 number of processes 只是一个考量因素,memory 与 I/O bandwidth 也算,就需要不断调优数值,和 @chocotan 说的 CPU-bound 还是 I/O-bound 系统有很大关系。但线程最大值不会超过 $kernel.pid_max。如果有不对的话麻烦大家指出来改一下哈😄
|
15
zsdroid 2018-09-17 15:21:31 +08:00
|
17
sagaxu 2018-09-17 15:44:30 +08:00 via Android
2 倍说的是 running 状态的线程,idle 的不算。运行队列深度不要超过 cpu 核心数的 2 倍,否则会有明显的性能下降。
idle 线程就算有几千个,也不会对性能有很大的影响。业务逻辑大都是同步阻塞模型,堆线程或者进程,十几年前,高校基于 telnet 协议的 bbs,每个在线用户对应一个进程,1 万在线就是 1 万个进程,当年配置很一般的服务器,也能搞定几千在线。 |
18
linshuang 2018-09-17 17:19:06 +08:00
1、前面那些拿网络 IO 跟服务器说事的,看看这句话吧——“做一个接口如果用多线程,数量都是 4000 个线程起”。都说是做接口了,明显跟这些玩意基本都不搭噶了,那些东西对他来说都是透明的。
2、万一说他写个接口真的是需要(协调)处理到网络 IO,只能说不愧大厂(啥都从头来),那样确实是需要开很多线程。 3、还有一种就是开线程花很少钱,但往往都是语言层面自带的,语言使用的是用户线程 |
19
wysnylc 2018-09-17 19:46:54 +08:00
IO 密集型开 10000 个我觉得也行
|
20
xvhfeng 2018-09-18 10:41:16 +08:00
这个问题?哪位同学用的是大型机吗?
线程和进程,基本的问题在于 OS 的支持,一般来说,不管你是 IO 密集型还是 CPU 密集型都不会开到 4000 个线程。就目前互联网企业尿性来说,机器不要说开到 4000 个线程,一般的接口开到 2000 线程都会有点累(注意,我说的是一般的接口)。从 OS 来说,4k 线程上下文的交换可能浪费掉了它原本 80%的性能,有点得不偿失。如果是 IO 密集型操作,完全可以不用走 CPU,应该也用不着 4k 线程来处理这些。如果 IO 密集型不走特殊硬件处理,那么应该也是多线程挂载多 event,然后通过生命周期将其操作拆开,这种方式才相对合理。否则别的请求不是都得饿死吗? 所以,这哥们可能只是酒桌上的一个玩笑,或者...... 好吧,还是要回去多看看 OS 的书。 |
21
ayonel OP 多谢各位大佬的回复,受益匪浅
|