type
status
date
slug
summary
tags
category
titleIcon
password
icon
calloutIcon
调度对象——Goroutine
  • Goroutine是用户空间线程 (完全由Go运行时管理,没有OS介入)
  • 轻量,开销小(更小的内存开销,更快的创建、销毁,上下文切换)
参考对比
notion image
为什么需要调度器?
由于Goroutine是用户层面的抽象,操作系统只认识内核线程。需要Go 调度器将多个 Goroutine 映射到实际的内核线程上。
对应会需要完成两项工作——Goroutine分发和创建线程。
notion image
Go 调度器的设计目标
  • 使用少量的内核线程:创建内核线程代价高昂,因此调度器力求高效地复用内核线程。
  • 支持高并发:Go 程序会涉及大量的 Goroutine,调度器需要满足这种需求。
  • 利用并行性:原则上在N核机器上,Go程序应能够并行N个Goroutine。
何时进行调度?
操作可能影响 Goroutine 执行时,Go 调度器就会介入
notion image
  • Goroutine 创建
  • Goroutine 阻塞:如等待channel或mutex
  • 系统调用: 阻塞的系统调用同时会阻塞内核线程
Go 调度器关键思想
  • 运行队列(runqueue): 等待运行的 Goroutine 被放置在队列中。最初,使用的是单个全局队列,但在多线程情况下会导致竞争问题。解决方案是分布式运行队列,每个线程都获取自己的队列。
  • 线程复用:空闲线程不进行销毁,会被用在检查全局运行队列、网络轮询、尝试运行gc任务、工作窃取上,如果仍然空闲会放置在一个链表中等待复用,以期最大利用并行性。
  • GOMAXPROCS:限制正在运行Goroutine的线程数为CPU逻辑核心数。
  • 工作窃取(work-stealing):如果一个线程的本地运行队列为空,它可以随机“窃取”其他线程队列中一半的任务,平衡线程之间的工作负载。
  • 移交(hand-off): 当一个线程被阻塞(例如,由于系统调用)超过一段时间时,它关联的运行队列会由“sysmon”转交到另一个线程,此时唤醒(Unpark)可复用的线程,如果需要的话创建新线程(线程数限制只适用于正在运行Goroutine的线程),防止 Goroutine 饥饿。
  • 协作式抢占: Go 调度时间节点依赖于程序自发调用调度器。但如果一个 Goroutine 长时间占用 CPU 不放,会由“sysmon”后台线程检测到(>10ms运行,警告)在可能的情况下抢占并将其放置于全局运行队列,确保公平性并防止饥饿。
  • 全局运行队列: 全局运行队列充当被抢占的 Goroutine 的低优先级队列。
  • “sysmon”线程:检测长时间运行的Goroutine,移交运行队列。
Go 调度过程示例
notion image
局限性
  • 没有 Goroutine 优先级: 所有 goroutine 都被平等对待,这在某些任务需要更高优先级的情况下可能会出现问题。
  • 没有强抢占: 协作式抢占无法保证公平性或延迟。
  • 对硬件拓扑的感知有限: 调度器目前缺乏对底层硬件拓扑的感知,局部性利用程度不高。
参考资料与扩展阅读
 
前端面试题整理面向ACGN人士的英语娱乐学习方案
Loading...
CamelliaV
CamelliaV
Java;CV;ACGN
最新发布
单例模式的四种写法
2025-4-24
体验MCP
2025-4-24
MetingJS使用自定义音乐源-CF+Huggingface部署
2025-4-2
博客访问站点测速分析与对比
2025-3-26
前端模块化
2025-3-16
Voxel2Mesh相关论文精读与代码复现
2025-3-15
公告
计划:
  • LLM相关
  • 支付业务 & 双token无感刷新
  • (线程池计算优惠方案)天机学堂Day09-Day12复盘-优惠劵业务
  • (业务复盘,技术汇总)天机学堂完结复盘
  • hot 100
 
2024-2025CamelliaV.

CamelliaV | Java;CV;ACGN