runtime.NumCPU()返回操作系统报告的逻辑CPU数量,含超线程,启动时固定读取,不感知容器cgroups限制,非物理核心数,也不能反映真实可用并发能力。

runtime.NumCPU() 返回的是操作系统报告的逻辑 CPU 数量,不是物理核心数,也不是当前容器或 cgroups 限制后的可用数。它在程序启动时读取一次,之后不会变。
runtime.NumCPU() 返回什么
这个函数返回的是 OS 层面的 逻辑处理器数量,即包含超线程(SMT)后的总数。比如一台 8 核 16 线程的机器,runtime.NumCPU() 通常返回 16。
它不区分物理核心与逻辑线程,也不感知容器限制 —— 即使你在 Docker 中用 --cpus=2 限制了资源,runtime.NumCPU() 依然返回宿主机的逻辑核数。
- Linux/macOS 下可对比
nproc或sysctl -n hw.ncpu验证是否一致 - Windows 上依赖
GetSystemInfo()系统调用,结果也属逻辑核 - 该值仅用于参考,不能直接等同于“可用并发能力”
为什么不能直接用 NumCPU 做性能判断
很多人误以为 runtime.NumCPU() 能反映当前程序“能跑多快”,其实它只是调度单位上限,和实际并发效率无关。
真正控制并行度的是 runtime.GOMAXPROCS(0) 的返回值,它表示当前生效的 P(processor)数量,而这个值可以被 GOMAXPROCS 环境变量或代码中显式调用修改。
-
runtime.NumCPU()启动时固定;runtime.GOMAXPROCS(0)可动态变化 - 在 Kubernetes Pod 中,若 cgroups 限制了 CPU quota,应优先查
/sys/fs/cgroup/cpu/cpu.max,而非依赖NumCPU - 做绑核或 NUMA 感知调度时,
NumCPU完全不够用,需用gopsutil/cpu.Info()获取 socket/core/thread/numa_node 映射
想获取物理核心数或 NUMA 拓扑怎么办
标准库不提供物理核心或拓扑信息,必须绕道系统接口或第三方库。
生产环境推荐用 github.com/shirou/gopsutil/cpu,它已封装好跨平台解析逻辑:
infos, _ := cpu.Info()
for _, info := range infos {
fmt.Printf("CPU%d: Socket=%d Core=%d NumaNode=%d\n",
info.CPU, info.SocketID, info.CoreID, info.NumaNode)
}
- Linux 下
NumaNode来自/sys/devices/system/node/,真实可用 - Windows/macOS 中
NumaNode固定为-1,需另寻方案 - 若拒绝外部依赖,可手动执行
grep "core id" /proc/cpuinfo | sort -u | wc -l(仅 Linux)
逻辑核数容易拿,但物理拓扑、NUMA 归属、cgroups 限制这些才是高并发服务真正要对齐的关键点。别让 runtime.NumCPU() 给你一种“我已经掌握硬件”的错觉。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











