关于htop中线程CPU占比总和与进程CPU占比不相等的技术疑问
问题描述
在下面的htop输出中,进程/home/jxz/server的CPU使用率达到了183%,但把显示出来的子线程的CPU占比加起来,却远达不到这个数值,这是为什么?
PID△USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command 619077 jxz 20 0 14.9G 2879M 62324 S 0.0 18.4 0:00.02 │ │ │ ├─ PtyProcess Reap 619079 jxz 21 1 290M 47184 20608 S 183. 0.3 40:53.94 │ │ │ └─ /home/jxz/server 619084 jxz 20 0 290M 47184 20608 S 0.0 0.3 0:00.00 │ │ │ ├─ bench 619085 jxz 20 0 290M 47184 20608 S 0.0 0.3 0:00.00 │ │ │ ├─ default-executo 619086 jxz 20 0 290M 47184 20608 S 0.0 0.3 0:00.00 │ │ │ ├─ resolver-execut 619087 jxz 20 0 290M 47184 20608 S 0.0 0.3 0:00.04 │ │ │ ├─ grpc_global_tim 619088 jxz 20 0 290M 47184 20608 S 0.7 0.3 0:47.56 │ │ │ ├─...
解答
嘿,这个问题我之前排查类似场景时也碰到过,咱们来拆解几个核心原因:
线程列表被截断了:你看输出末尾的
...,这说明htop当前只展示了该进程的部分线程,还有大量线程没显示出来。那些隐藏线程的CPU消耗没被算进你手动求和的数值里,但进程的总CPU占比是包含所有线程的。你可以在htop里按下H键(切换显示所有线程),就能看到完整的线程列表,这时候再求和就会和进程的183%CPU占比基本匹配了。采样时间差带来的偏差:htop是定期(默认1-2秒)从内核拉取数据的,进程的总CPU占比是统计整个采样周期内所有线程的CPU消耗总和,而每个线程的CPU数据采样和进程总数据的采样可能存在微小时间差——如果某些线程在采样间隔内快速切换状态(比如从高负载瞬间变空闲),就会出现临时的数值不匹配。
短暂存活的线程没被捕获:有些线程可能在两次采样之间启动、完成任务然后退出了,这些线程不会出现在htop的线程列表里,但它们运行时消耗的CPU已经被统计到进程的总CPU占比中,这也会导致手动求和的结果偏小。
内核统计的细微精度差异:进程的CPU统计是内核直接给出的进程级总消耗,而线程的CPU是每个线程的单独统计值,两者在计算时可能存在极微小的精度差异,比如上下文切换的开销统计、内核态/用户态的计数边界等,但这种差异一般不会特别明显。
你也可以用ps -L -p 619079命令(把619079换成你的进程PID)来查看该进程所有线程的CPU占比,手动求和后应该就会和htop里显示的进程总CPU占比基本一致了。
备注:内容来源于stack exchange,提问作者rafoo

