runtime.NumCPU()返回逻辑CPU数,非物理核数,直接用作coreID易越界报EINVAL;绑定需先LockOSThread再调SchedSetaffinity,否则因goroutine迁移而失效。
返回的是逻辑 CPU 数量,不是物理核心数,更不等于可用绑定目标——直接用它当
传给
很可能越界报
。真要绑 CPU,得先确认系统实际拓扑,再按需锁定 OS 线程 + 设置亲和性,否则绑定无效或反拖慢性能。
为什么 goroutine 直接调
没用
Go 的 goroutine 是用户态协程,调度器随时可能把它从当前 M(OS 线程)上换走,换到另一个 M 上运行。而
绑定的是**当前 OS 线程**,不是 goroutine。所以:
必须先调
,把当前 goroutine 和它正在跑的 OS 线程锁死
再立刻调
(
表示当前线程)
如果中途没锁住、或锁住后又 unlock 了,绑定就失效
常见错误:在
里直接绑,没锁线程,绑的其实是启动 goroutine 的那个临时 M,极不稳定
超出范围就 panic?看清楚
的含义
返回的是
的值,即当前在线的逻辑 CPU 数(含超线程)。但它不反映:
CPU 是否被内核隔离(如
启动参数屏蔽的核)
NUMA 节点分布(比如 48 核机器,但
显示是 2×24,跨节点绑核会触发远端内存访问)
容器或 cgroup 限制(
可能只暴露 0-3,但
还返回 48)
安全做法是:先读
或用
确认可用 core 列表,再选其中某个 ID;别硬套
。
立即学习
“
go语言免费学习笔记(深入)
”;
go语言参考手册 中文CHM版
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译
下载
绑完 CPU,QPS 反而掉了一半?检查这几个点
盲目绑定最常导致性能倒退,尤其在压测场景:
client 和 server 都绑了同一颗核(比如都绑
),实际变成串行竞争,不是隔离
网络密集型服务绑单核后,netpoller 和 timer goroutine 被卡住,导致 accept 延迟飙升
没配
,绑在 node1 的核却访问 node0 的内存,延迟翻倍
用
限制 M 数,又绑死线程,一旦 goroutine 进 syscal 就阻塞整个 M,新请求进不来
压测前建议:用
看 task 是否真没迁移;用
看 G 是否长期处于
或
状态。
真正需要 CPU 绑定的场景极少——通常是低延迟交易、实时音视频编码、或与硬件设备直通的驱动层程序。多数 Web 服务靠 Go 自身调度器就够了;硬绑反而破坏 runtime 对 M/P/G 的动态平衡。如果非绑不可,优先用
启动整个进程,比在代码里 syscall 更稳。
runtime.NumCPU()coreIDsyscall.SchedSetaffinityEINVALsyscall.SchedSetaffinitysyscall.SchedSetaffinityruntime.LockOSThread()syscall.SchedSetaffinity(0, &cpuSet)0go func() { ... }()coreIDruntime.NumCPU()runtime.NumCPU()sysconf(_SC_NPROCESSORS_ONLN)isolcpus=numactl -Hcpuset.cpusNumCPU()/sys/devices/system/cpu/onlinenumactl --showNumCPU()-10numactl --membinddebug.SetMaxThreads(1)perf record -e sched:sched_migrate_taskgo tool traceSyscallRunnablenumactl