每日一Go-38、深入Goroutine--调度器G/M/P机制与调度策略
Go 的并发优势很大程度上来自 用户态调度器(Goroutine Scheduler)。它不依赖 OS 线程创建大量轻量级任务,通过 G/M/P模型 和智能调度策略保证高吞吐、低延迟。 一、为什么需要 Go 调度器? 操作系统的线程有两个天然缺陷 而Go的调度器能做到: 二、G / M / P 模型详解 Go调度器用三个核心实体表示执行模型 1. G - Goroutine 2. M - Machine (操作系统线程) 3. P - Processor (逻辑处理器) 三、G 的生命周期(敲黑板) 最重要的两个状态转换: 3.1 running -> waiting : G会从P的队列里消失,即标记为waiting状态 3.1.1 channel里没有数据/不能发送--等别人 3.1.2 mutex已经被别人锁住--等锁 3.1.3 IO要等系统返回--等网络/磁盘 3.1.4 明确休眠--等事件 3.2 waiting -> runnable :把G唤醒 3.2.1 channel有数据了/能发送了 把等待的G放回队列,状态改为runnable 3.2.2 mutex解锁了 这个时候,调度器会查看有没有goroutine因为这个锁阻塞,有的话就唤醒它并返回队列 3.2.3 netpoll:网络IO就绪了 当epoll/kqueue发现socket可以读/写 内核就通知Go运行时,运行时把对应的G标记为runnable,并放入可运行队列里 3.2.4 timer到点了 time.Sleep结束后,timer管理器发现时间到了,把对应的G唤醒,重新放到P的可运行队列里 四、调度循环(抢工作+ 本地队列优先) Go的调度器使用组合策略,核心要点: 4.1 优先从本地P队列取G 4.2 本地队列空了就去抢任务,从其他P抢一半goroutine 4.3 新建G优先放入本地队列 4.4 syscall/unblock G,可能丢到全局队列 4.5 定期检查全局队列,只在需要的时候取任务 整体思路:尽可能在本地消化任务,没有任务就去抢,确保所有P都不会闲着。 五、调度触发点(什么时候会调度?) Go调度不是随时都切换,调度仅发生在特定时机: 5.1 主动让出 5.2 阻塞操作 一旦发送阻塞,就会触发调度,调度器会把协程变成waiting 5.3 函数调用边界 Go会在函数调用入口插入检查点,当一个G运行太久,调度器就会发抢占信号,在下一个函数调用点检查到信号,就会自动让出 5.4 GC安全点 GC需要STW或扫描所有栈,这也会触发抢占。 六、调度器的图示说明(ASCII) 七、经典问题解析 7.1 Go能否用多线程跑同一个goroutine? 答:不能,每个G在任意时刻只能在一个M上运行。调度点可以迁移,但不会并行执行。 7.2 Go会频繁切换goroutine吗? 答:不会,Go的调度是协作式+抢占式混合;多数切换发生在阻塞点,少量切换在函数入口抢占点。 7.3 为什么设置GOMAXPROCS大了反而变慢? 答:因为P=并发能力。P增多就会导致更多队列、更多抢任务、更多GC、更多竞争。一半设置为CPU核心数是最佳。 Goroutine 调度器就像一个巨大餐厅:P 是厨房,M 是厨师,G 是订单。厨师想做菜必须占到厨房;订单在每个厨房的本地栏里排队,没订单的厨房可以跑去别的厨房抢订单,保证每个厨房都不闲着。 *源码地址* 1、公众号“Codee君”回复“每日一Go”获取源码 2、https://pan.baidu.com/s/1B6pgLWfSgMngVeFfSTcPdg?pwd=jc1s 如果您喜欢这篇文章,请您(点赞、分享、亮爱心),万分感谢!
new
->
->
running
->
->
->
-><-ch //阻塞 ch <- v // 阻塞Lock
//锁住Read
// netpoll等待系统通知time
.Sleepmu.Unlock()Gosched
//告诉调度器,我先不跑了,你切出去吧 ┌──────────┐
│ Global │
│ RunQueue │
└─────┬────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
┌─────┐ ┌─────┐ ┌─────┐
│ P0 │ │ P1 │ │ P2 │ ... (P = GOMAXPROCS)
└─┬───┘ └──┬──┘ └──┬──┘
│ │ │
LocalRQ LocalRQ LocalRQ
│ │ │
▼ ▼ ▼
┌───┐ ┌───┐ ┌───┐
│ M │ │ M │ │ M │ (OS Thread)
└─▲─┘ └─▲─┘ └─▲─┘
│ │ │
└─────────┴──────────┘
Syscalls, Block, Wakeup