
今天聊一个后端面试必考的高频硬核知识点:Go 语言的 GMP 调度模型。我会用大白话把 G、M、P 是什么、调度流程、阻塞处理、work stealing 等细节拆开讲清楚。另外还附带 Channel、GC、MySQL 索引、Redis 等常考内容,帮你一次备全。
面试官只要问“Go 的并发原理”,99% 会接着问 GMP。你需要从概念 → 调度流程 → 阻塞场景 → 优化机制 逐层讲透。
组件 | 全称 | 作用 | 类比 |
|---|---|---|---|
G | Goroutine | 代表一个任务,包含栈、指令指针、状态等信息 | 待执行的“函数包裹” |
M | Machine | 内核线程,真正执行代码的实体 | 干活的人 |
P | Processor | 逻辑处理器,持有本地 G 队列,负责调度 | 人的“任务篮子” |
关键约束:
GOMAXPROCS 决定,默认等于 CPU 核数当 P 的本地队列为空时:
len(GRQ)/GOMAXPROCS + 1 个)conn.Read)结果:没有系统调用阻塞,没有线程切换,高效。
time.Sleep)_Gsyscall这种机制叫 hand off:P 不等待慢系统调用,立即转移给其他 M,保证 CPU 利用率。
mutex.Lock 竞争失败)_GwaitingGOMAXPROCS 个自旋线程原因 | 例子 | 后果 |
|---|---|---|
无缓冲 channel 读写未配对 | 两个 G 都在等对方发 | 两个 G 永远挂起 |
锁未释放 | mu.Lock() 后 return 没有 Unlock | 等待该锁的所有 G 永久阻塞 |
WaitGroup 计数错误 | Add(1) 但 Done() 少调用一次 | 调用 Wait() 的 G 永远等 |
网络 I/O 无超时 | conn.Read 对方不响应 | G 永久阻塞在 netpoller |
死循环 | for {} 且没有让出 CPU | 虽然 Go 1.14 后支持抢占,但仍有极端情况 |
解决套路:
defer 保证解锁 / Donecontext.WithTimeout、time.After“GMP 中 G 是 goroutine,M 是内核线程,P 是逻辑处理器。P 的数量默认等于 CPU 核数,每个 P 有一个本地 G 队列。调度时 P 优先从本地队列取 G 绑定 M 执行;本地队列空了就从全局队列或偷取其他 P 的任务。遇到网络 I/O 阻塞时,G 被 netpoller 挂起,P 立即去执行其他 G;遇到系统调用阻塞时,当前 M 带着 G 进内核,P 会解绑并 hand off 给另一个 M,保证 CPU 不空转。这样设计使得 Go 可以轻松支持数十万并发。”
select 多路复用 + 超时 / 退出监听close(ch) 广播案例一:批量数据接收 车辆上报数据 → 写入 channel → 4 个 worker 解析入库 → 扛住高峰流量
案例二:服务安全退出 监听 SIGTERM → 退出 channel 通知所有 G 停止新任务 → 等待当前任务完成 → 释放资源
对比维度 | 进程 | 线程 | goroutine |
|---|---|---|---|
资源占用 | 最重 | 中等(栈 ~1MB) | 极轻(栈 ~2KB,可扩容) |
创建/销毁 | 内核态,慢 | 内核态,慢 | 用户态,快 |
调度 | 内核 | 内核 | Go runtime(协作+抢占) |
并发能力 | 几百 | 几千 | 几十万 |
结论:goroutine 足够轻,一台服务器轻松几十万个。
time.Sleep自动回收堆上不再被引用的对象。栈上的变量随函数返回自动释放。
make([]int, n),n 是变量)并发三色标记清除 + 混合写屏障。标记可达对象为黑色,回收白色对象,与用户代码并发。
调整 GOGC,使用 sync.Pool 复用对象。
对比项 | 二叉搜索树 | B 树 | 哈希表 | B+ 树 |
|---|---|---|---|---|
树高 | 高 | 中 | - | 低 |
磁盘 I/O | 多 | 中 | 少(仅等值) | 少 |
范围查询 | 一般 | 需回溯 | 不支持 | 高效(叶子链表) |
插入:叶子节点满则分裂,中间 key 上移,递归至根 → 树高可能增加 删除:节点 key 不足则先借后合并,递归至根 → 树高可能减少
类型 | 底层 | 场景 | 命令 |
|---|---|---|---|
String | SDS | 缓存、锁、计数器 | SET, GET, INCR |
Hash | 压缩列表/哈希表 | 对象属性 | HSET, HGET |
List | 双向链表/快表 | 消息队列 | LPUSH, RPOP |
Set | 整数集合/哈希表 | 标签 | SADD, SISMEMBER |
ZSet | 跳表+哈希表 | 排行榜 | ZADD, ZREVRANGE |
Bitmap | SDS 按位 | 签到 | SETBIT, GETBIT |
SDS 优势:O(1) 长度,二进制安全。
GMP 是 Go 面试的分水岭。能讲清楚调度流程、阻塞处理、work stealing、hand off 机制,面试官就会认可你的底层功底。其他知识点也建议结合项目经验说,不要背概念。