深入解析Golang GMP模型:抢占式调度机制
Golang 的并发能力源于其独特的 GMP 模型,它是 Go 语言调度器实现的基础。GMP 模型由 Goroutine(G)、Machine(M)和 Processor(P)三部分组成:
-
Goroutine(G): 可以理解为轻量级线程,是 Go 实现高并发的基石。每个 Goroutine 有唯一的 ID (goid),由 Go 运行时而非操作系统直接管理。
-
Machine(M): 代表操作系统线程,负责执行 Goroutine。每个 M 都有自己的本地队列,存储待执行的 Goroutine。
-
Processor(P): 逻辑处理器,管理 M 的执行。P 将 Goroutine 分配给 M,确保每个 M 都有任务可执行。
Golang 调度器采用抢占式调度机制,确保 Goroutine 在不同 M 之间切换,保证执行效率和公平性。抢占调度主要步骤如下:
-
创建 Goroutine: 使用
go
关键字调用runtime.newproc()
函数创建 Goroutine。 -
Goroutine 状态变化: 新建的 Goroutine 处于可运行状态,加入本地队列。若本地队列已满,则加入全局队列。
-
调度时机: 新建协程、协程执行完阻塞的系统调用(如文件IO、网络IO、channel、mutex等)、
time.sleep
、垃圾回收后主动调用runtime.Gosched()
等。 -
Machine 执行: 每个 M 执行本地队列中的 Goroutine。若本地队列为空,则从全局队列获取。若全局队列也为空,则尝试从其他 M 的本地队列窃取任务 (work stealing)。
抢占式调度使 Goroutine 能够在多个 M 之间灵活切换,防止某个 Goroutine 长时间占用资源,从而提高整体性能。
评论区