百度二面:Go 语言 GMP 模型面试题解析

大家好,我是老周,今天跟大家分享的是一道关于 Go 语言 GMP 模型的面试题。这是一道百度二面的面试真题,核心问题是 “GMP 模型中的 work stealing(工作窃取)机制会偷多少个 G(协程)”。如果不了解 GMP 模型,可能连 “偷多少” 是什么意思都不清楚。下面我们将从 GMP 模型的基础概念开始,逐步拆解这个问题。

一、GMP 模型核心概念

首先要明确 GMP 三个字母分别代表的含义,这是理解后续逻辑的基础:

  • G(Goroutine):即 Go 语言中的协程,是轻量级的执行单元,也是我们调度和执行的核心对象。当我们编写go function()这样的代码时,本质就是创建了一个 G(协程)。
  • M(Machine):对应操作系统的内核线程,是真正执行代码的 “载体”。G 需要绑定到 M 上才能被 CPU 调度执行,也就是说,G 的逻辑最终要通过 M(内核线程)来落地运行。
  • P(Processor):即调度器,负责管理 G 的队列并将 G 分配给 M 执行。需要注意的是:P 和 M 是 “一对一绑定” 的关系,一个 P 只能对应一个 M,一个 M 也只能绑定一个 P。我们平时给 Go 应用程序设置 “最大进程数”(实际是GOMAXPROCS参数),本质就是设置 P 的数量 ——P 的数量直接决定了 Go 程序能同时利用的 CPU 核心数(默认等于 CPU 核心数)。

二、G(协程)的入队逻辑

创建 G 之后,需要将其放入队列等待调度,Go 设计了 “本地队列” 和 “全局队列” 两种存储结构,优先级和性能有明显区别:

1. 优先放入本地队列

每个 P(调度器)都有一个专属的本地队列,特点是:

  • 无锁设计:因为本地队列只归当前 P 所有,其他 P 或 M 不会访问,不需要加锁保护,性能更高,能避免资源竞争。
  • 分配规则:创建 G 时,会优先将 G 放入 “本地队列中 G 数量较少” 的 P 中(即 “哪个 P 的本地队列空 / 数量少,就放哪个”),尽量保证各 P 的任务负载均衡。

2. 本地队列满时,放入全局队列

如果所有 P 的本地队列都已满(达到队列容量上限),则会将 G 放入全局队列,特点是:

  • 加锁设计:全局队列是所有 P 共享的,多个 P 访问时会存在资源竞争,必须通过加锁保证线程安全,因此性能比本地队列低。

三、G(协程)的出队与调度逻辑

P 会不断从队列中取出 G,分配给绑定的 M 执行,出队顺序遵循 “本地优先、全局补充、窃取兜底” 的规则:

1. 优先消耗本地队列的 G

P 首先会处理自己本地队列中的 G,按顺序取出 G 并分配给绑定的 M,M 执行 G 的逻辑(本质是调用 G 对应的函数)。

2. 本地队列为空时,从全局队列取 G

如果 P 的本地队列为空,会去全局队列中 “取一批 G”,填充到自己的本地队列,再继续执行调度。

3. 全局队列也为空时,触发 work stealing(工作窃取)机制

如果 P 的本地队列和全局队列都没有 G,但发现其他 P 的本地队列中还有较多 G,就会触发work stealing 机制

  • 核心逻辑:当前 P 会从 “有剩余 G 的其他 P 的本地队列” 中,窃取一半的 G,放入自己的本地队列,之后再从自己的本地队列中取 G 分配给 M 执行。

四、面试题答案

回到百度二面的核心问题 ——“GMP 模型中 work stealing 机制会偷多少个 G?”

答案:当某 P 的本地队列和全局队列都为空时,会通过 work stealing 机制,从其他 P 的本地队列中窃取一半的 G,补充到自己的本地队列中。

以上就是今天的Go 语言 GMP 模型面试题解析分享,希望对大家有所帮助。

#it##计算机##程序员##golang#
全部评论
前面说了本地队列不会被其它 P 和 M 访问到,才设计成无锁 那偷任务的时候不需要访问被偷的 P 的本地队列吗
1 回复 分享
发布于 09-19 16:46 北京

相关推荐

没有自我介绍 全程八股go基础方面1. 切片和数组的区别2. map的删除(假删除)3. GMP4. 协程和进程、线程的区别5. channel的阻塞、非阻塞mysql1. 了解底层吗 为什么用b+树2. 回表查询3. 事务的隔离级别 脏读 不可重复读4. redolog undolog binlog5. 分库分表怎么分 键是怎么移过去的(一致性哈希 忘了)redis1. 了解什么数据结构2. 分布式锁3. 缓存穿透、击穿、雪崩mq重复消费怎么解决计网1. ip和tcp分别是哪层的2. tcp和udp的区别3. http和https的区别 只答了加密 还把加密协议名记错了 安全证书没说4. 从输入地址到显示页面的过程 dns+http5. 状态码 502和504的区别操作系统 面的时候可以说基本没看 吃大亏1. 进程间通信 只答了管道 共享内存和信号量2. 死锁的四个条件 非抢占想了半天才想起来3. 进程的调度 答:进程是由内核调度的 我真的服了linux平时用的什么linux指令 怎么定位线程、进程的使用情况 没答出来场景题 设计秒杀用redis作缓存+分库分表(想说读写分离说错了) mq削峰 用rocketmq或者kafka这种吞吐10w+的因为提了redis分库分表,后面问lua脚本能不能原子性 分布式环境不能 要加上分布式锁下单超时 返回的订单给接下来哪个用户 没听明白 用消息队列的延迟队列来做下单超时(答非所问)算法1. 了解什么排序算法 只答了冒泡和快拍😭排序这一块真不行 问了时间复杂度和哪个稳定2. 链表删除倒数第n个节点 太紧张忘了快慢指针怎么做 转正向删除做了总结八股感觉还可以 就操作系统基本没看吃大亏 算法还行起码做出来 收了我吧😭
查看28道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务