当前位置: 首页 > news >正文

Go 是如何做抢占式调度的?

一、什么是“抢占式调度”?

先理解什么是“抢占”。

非抢占式(早期 Go)

早期 Go(1.14 之前):

  • goroutine 只有在

    • 函数调用
    • channel 操作
    • syscall
    • runtime 检查点

才会被切换。

如果一个 goroutine 写成:

for {
}

会发生什么?

👉 它永远不会让出 CPU
👉 其他 goroutine 全部饿死

这叫:

协作式调度(主动让出)


抢占式调度

抢占式调度是:

即使 goroutine 不愿意让出 CPU,调度器也可以强制打断它

这就是现代 Go(1.14+)的机制。


二、Go 现在是如何“强制打断”的?

核心答案:

通过“信号 + 栈检查”实现异步抢占

我们拆开讲。


三、抢占的触发条件

Go 会给每个运行中的 goroutine 设置一个“时间片”。

大概:

10ms 左右

如果:

某个 G 连续运行超过时间片

调度器就会尝试抢占它。


四、真正的技术实现(关键来了)

Go 通过:

发送操作系统信号(SIGURG)

去打断正在运行的线程 M。

步骤如下:


第一步:标记需要抢占

调度器发现:

这个 G 运行太久了

就会:

g.preempt = true

标记它需要被抢占。


第二步:给 M 发信号

Go runtime 会向正在运行的 M 发送一个系统信号:

SIGURG

这会打断线程执行。


第三步:信号处理函数触发

当 M 收到信号时:

会执行 Go runtime 的信号处理函数。

这个函数会:

  1. 保存当前寄存器状态
  2. 检查是否可以安全抢占
  3. 修改程序计数器
  4. 跳转到调度函数

五、什么叫“安全抢占点”?

Go 不能在任何地方强行打断。

比如:

  • 正在修改栈
  • 正在执行 runtime 内部关键代码
  • 正在 GC 关键阶段

所以必须在“安全点”抢占。

Go 在函数调用前后插入:

栈边界检查

类似:

CMP SP, stackGuard

如果发现:

  • 栈溢出
  • 或被标记需要抢占

就跳到 runtime。

这就实现了:

在几乎所有函数调用处都可被抢占


六、为什么 1.14 是重大升级?

1.14 之前:

  • 只能在函数调用点抢占
  • 死循环没函数调用就无法抢占

1.14 之后:

  • 加入“异步抢占”
  • 即使死循环也可以被打断

例如:

for {
}

现在也会被强制暂停。


七、完整抢占流程(一步一步)

假设:

G1 正在运行

1️⃣ G1 运行超过 10ms
2️⃣ 调度器标记 G1 需要抢占
3️⃣ 给 M 发送信号
4️⃣ M 收到信号
5️⃣ 保存当前执行现场
6️⃣ 切换到 runtime 调度代码
7️⃣ G1 状态改为 runnable
8️⃣ 放回队列
9️⃣ 执行其他 G


八、和操作系统抢占有什么区别?

操作系统线程调度:

  • 由内核控制
  • 时间片强制切换线程

Go goroutine 调度:

  • 用户态调度
  • 通过信号模拟“线程级抢占”
  • 更轻量

九、为什么这样设计?

目标是:

  • 防止 goroutine 独占 CPU
  • 保证公平性
  • 提高多核利用率
  • 让 GC 可以安全暂停世界

尤其是 GC:

如果不能抢占 goroutine:

STW(Stop The World)会卡死

十、和 GC 的关系

Go 的 GC 需要:

在安全点暂停所有 goroutine

抢占机制保证:

  • 即使 goroutine 死循环
  • GC 也能暂停它

这非常关键。


十一、核心总结

一句话版本:

Go 通过向线程发送信号,在安全点打断 goroutine,实现异步抢占式调度。

再浓缩:

时间片到
→ 标记抢占
→ 发信号
→ 跳到调度器
→ 切换 goroutine

十二、一个形象比喻

想象:

  • G 是学生
  • M 是老师
  • P 是教室

以前:

学生必须自己举手说“我讲完了”。

现在:

老师可以直接打断学生:

“时间到了,换人!”

这就是抢占式调度。

http://www.jsqmd.com/news/355924/

相关文章:

  • 【小程序毕设全套源码+文档】基于Android的大学生勤工助学管理系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • Kaggle Binary Classification with a Bank Dataset逻辑回归完成(准确率0.94539)
  • 盒马鲜生礼品卡回收时需要注意哪些问题呢? - 京顺回收
  • 2026年2月进口发电机出租公司推荐榜,原装设备租赁企业实测榜 - 品牌鉴赏师
  • 效果比较好的生发机构推荐-黑奥秘以慢病管理打造毛发养护体系
  • 市面上的生发养发馆管用吗?黑奥秘近20年深耕,慢病管理逻辑破解生发难题
  • 如何理解 Go 的调度模型,以及 G / M / P 各自的职责
  • Redis数据类型的底层实现和数据持久化
  • 基于机器学习的眼底图像糖尿病视网膜病变诊断系统-大数据深度学习算法毕设毕业设计项目PyQt
  • 基于卷积神经网络的地震数据破碎带识别方法研究-大数据深度学习算法毕设毕业设计项目PyQT
  • P2367 语文成绩
  • 2026年国内超声波振动筛厂家全景盘点及实力解析 - damaigeo
  • 2026年2月大型活动发电机租赁公司最新推荐,定制化供电方案与现场保障优选榜 - 品牌鉴赏师
  • 【无标题】vlan
  • 深入浅出:使用Linux系统函数构建高性能TCP服务器
  • 生发机构哪个更有效?黑奥秘AI智能检测,千人千方更高效
  • AI元人文构想理论体系全球思想学术综述
  • 2026年2月木模板厂家最新推荐,权威测评与实木板材品质把控指南 - 品牌鉴赏师
  • 我电脑上安装了androidstudio 但是我不知道adb 安装在哪个路径下,如何找到 windows11
  • Qt 帮助文档为空问题(查询无结果)
  • 深入解析:串口无线数传模块:实现汽车零部件厂房 PLC 与触摸屏 300 米稳定交互
  • 超声波振动筛厂家怎么选?核心标准+标杆品牌推荐 - damaigeo
  • 斑马优化算法优化BP神经网络风电功率预测附Matlab代码
  • 【Hadoop+Spark+python毕设】基于大数据的车辆二氧化碳排放量可视化分析系统、计算机毕业设计、包括数据爬取、数据分析、数据可视化、实战教学
  • 青岛华硕笔记本维修点_青岛华硕电脑售后服务网点查询 - damaigeo
  • 第七日笔记
  • 深浅拷贝、STL迭代器失效 - 教程
  • 史上最大规模CNV研究:47万人全基因组测序揭示疾病新线索
  • Java面向对象——抽象类
  • 生发养发馆哪家效果好?黑奥秘三位一体理念+标准化服务保障品质