本文源码版本基于 go1.21.13
代码有点多,只是简单介绍下 G、M、P 每个的结构体
GMP 简介:https://blog.twelveeee.top/2023/Go/go GMP intro/
本文基于 Go 1.21.13 的 runtime2.go 源码,梳理了 Go 调度器中的 G (goroutine)、M (machine)、P (processor) 三个核心结构体,以及全局调度器 schedt 的关键字段。
- G (goroutine):是 Go 的用户态线程,封装了栈、调度上下文、panic/defer 链表、状态流转标识及 GC 相关信息,是用户代码运行的最小执行单元。
- M (machine):抽象操作系统内核线程,负责实际执行 G。它与 P 绑定,利用自己的 g0 栈来运行调度逻辑,并维护与调度、信号、cgo 调用等相关的上下文。
- P (processor):是 M 执行 Go 代码的必需上下文,维护着本地运行队列、本地内存分配缓存、定时器及 GC 写屏障等状态,它保证了 M 在运行时能高效管理 goroutine 与内存。
- schedt:作为全局调度器,统一管理空闲 / 运行中的 G、M、P 队列,协调 GC、STW、安全点、以及负载均衡,保证整个 GMP 系统的正常运转。
整体来看,Go 调度的核心思想是:G 是任务单元,M 是执行者,P 负责调度上下文和资源,schedt 做全局协调。这种 GMP 模型保证了 goroutine 调度的高并发性和轻量级,避免了对 OS 线程的过度依赖。
# G
Go runtime 里调度器 G (goroutine) 的实现,是承载用户协程的核心数据结构,记录了 goroutine 执行所需的各种上下文信息。
# Goroutine 基本字段
基本字段包括 栈与函数执行环境管理,异常处理机制(panic/defer),调度上下文保存,状态流转与调度控制,GC 协作与内存安全,运行时辅助信息 等
type g struct { | |
stack stack | |
stackguard0 uintptr | |
stackguard1 uintptr | |
_panic *_panic | |
_defer *_defer | |
m *m | |
sched gobuf | |
syscallsp uintptr | |
syscallpc uintptr | |
param unsafe.Pointer | |
stktopsp uintptr | |
atomicstatus atomic.Uint32 | |
stackLock uint32 | |
goid uint64 | |
schedlink guintptr | |
waitsince int64 | |
waitreason waitReason | |
preempt bool | |
preemptStop bool | |
preemptShrink bool | |
asyncSafePoint bool | |
paniconfault bool | |
gcAssistBytes int64 | |
gcscandone bool | |
throwsplit bool | |
activeStackChans bool | |
parkingOnChan atomic.Bool | |
raceignore int8 | |
tracking bool | |
trackingSeq uint8 | |
trackingStamp int64 | |
runnableTime int64 | |
lockedm muintptr | |
sig uint32 | |
writebuf []byte | |
sigcode0 uintptr | |
sigcode1 uintptr | |
sigpc uintptr | |
parentGoid uint64 | |
gopc uintptr | |
ancestors *[]ancestorInfo | |
startpc uintptr | |
racectx uintptr | |
waiting *sudog | |
cgoCtxt []uintptr | |
labels unsafe.Pointer | |
timer *timer | |
selectDone atomic.Uint32 | |
goroutineProfiled goroutineProfileStateHolder | |
trace gTraceState | |
} |
type _panic struct { | |
argp unsafe.Pointer | |
arg any | |
link *_panic | |
pc uintptr | |
sp unsafe.Pointer | |
recovered bool | |
aborted bool | |
goexit bool | |
} |
type _defer struct { | |
started bool | |
heap bool | |
openDefer bool | |
sp uintptr | |
pc uintptr | |
fn func() | |
_panic *_panic | |
link *_defer | |
fd unsafe.Pointer | |
varp uintptr | |
framepc uintptr | |
} |
type gobuf struct { | |
sp uintptr | |
pc uintptr | |
g guintptr | |
ctxt unsafe.Pointer | |
ret uintptr | |
lr uintptr | |
bp uintptr | |
} |
# Goroutine 状态流转
const ( | |
_Gidle = iota | |
_Grunnable | |
_Grunning | |
_Gsyscall | |
_Gwaiting | |
_Gmoribund_unused | |
_Gdead | |
_Genqueue_unused | |
_Gcopystack | |
_Gpreempted | |
_Gscan = 0x1000 | |
_Gscanrunnable = _Gscan + _Grunnable | |
_Gscanrunning = _Gscan + _Grunning | |
_Gscansyscall = _Gscan + _Gsyscall | |
_Gscanwaiting = _Gscan + _Gwaiting | |
_Gscanpreempted = _Gscan + _Gpreempted | |
) |

# M
m 是 Go runtime 里调度器 M (machine) 的实现,M 代表一个内核线程,实际上就是执行 goroutine 的 “物理承载者”。它和 P (Processor) 绑定,驱动 G (goroutine) 的执行。
# M 基本字段
基本字段包括 调度相关,执行栈与上下文保存,与操作系统交互,资源与生命周期管理,调试与监控
type m struct { | |
g0 *g | |
morebuf gobuf | |
divmod uint32 | |
_ uint32 | |
procid uint64 | |
gsignal *g | |
goSigStack gsignalStack | |
sigmask sigset | |
tls [tlsSlots]uintptr | |
mstartfn func() | |
curg *g | |
caughtsig guintptr | |
p puintptr | |
nextp puintptr | |
oldp puintptr | |
id int64 | |
mallocing int32 | |
throwing throwType | |
preemptoff string | |
locks int32 | |
dying int32 | |
profilehz int32 | |
spinning bool | |
blocked bool | |
newSigstack bool | |
printlock int8 | |
incgo bool | |
isextra bool | |
isExtraInC bool | |
freeWait atomic.Uint32 | |
fastrand uint64 | |
needextram bool | |
traceback uint8 | |
ncgocall uint64 | |
ncgo int32 | |
cgoCallersUse atomic.Uint32 | |
cgoCallers *cgoCallers | |
park note | |
alllink *m | |
freelink *m | |
schedlink muintptr | |
lockedg guintptr | |
createstack [32]uintptr | |
lockedExt uint32 | |
lockedInt uint32 | |
nextwaitm muintptr | |
waitunlockf func(*g, unsafe.Pointer) bool | |
waitlock unsafe.Pointer | |
waitTraceBlockReason traceBlockReason | |
waitTraceSkip int | |
syscalltick uint32 | |
trace mTraceState | |
libcall libcall | |
libcallpc uintptr | |
libcallsp uintptr | |
libcallg guintptr | |
syscall libcall | |
vdsoSP uintptr | |
vdsoPC uintptr | |
preemptGen atomic.Uint32 | |
signalPending atomic.Uint32 | |
dlogPerM | |
mOS | |
locksHeldLen int | |
locksHeld [10]heldLockInfo | |
} |
# P
P 是 Go runtime 里调度器 P (processor) 的实现,P 是协程调度的关键角色,它维护着与调度、内存分配、垃圾回收、定时器等多个方面相关的本地状态,可以看作是 "M 执行 G 的上下文环境"。
# P 基本字段
type p struct { | |
id int32 | |
status uint32 | |
link puintptr | |
m muintptr | |
raceprocctx uintptr | |
goidcache uint64 | |
goidcacheend uint64 | |
schedtick uint32 | |
syscalltick uint32 | |
sysmontick sysmontick | |
runqhead uint32 | |
runqtail uint32 | |
runq [256]guintptr | |
runnext guintptr | |
mcache *mcache | |
pcache pageCache | |
mspancache struct { | |
len int | |
buf [128]*mspan | |
} | |
deferpool []*_defer | |
deferpoolbuf [32]*_defer | |
sudogcache []*sudog | |
sudogbuf [128]*sudog | |
pinnerCache *pinner | |
gFree struct { | |
gList | |
n int32 | |
} | |
timer0When atomic.Int64 | |
timersLock mutex | |
timers []*timer | |
timerModifiedEarliest atomic.Int64 | |
numTimers atomic.Uint32 | |
deletedTimers atomic.Uint32 | |
timerRaceCtx uintptr | |
gcAssistTime int64 | |
gcFractionalMarkTime int64 | |
scannedStackSize uint64 | |
scannedStacks uint64 | |
maxStackScanDelta int64 | |
limiterEvent limiterEvent | |
gcMarkWorkerMode gcMarkWorkerMode | |
gcMarkWorkerStartTime int64 | |
gcw gcWork | |
wbBuf wbBuf | |
runSafePointFn uint32 | |
trace pTraceState | |
palloc persistentAlloc | |
statsSeq atomic.Uint32 | |
preempt bool | |
pageTraceBuf pageTraceBuf | |
} |
# P 状态流转
const ( | |
_Pidle = iota | |
_Prunning | |
_Psyscall | |
_Pgcstop | |
_Pdead | |
) |

# schedt
schedt 是 全局唯一的调度器实例,保存了 Go 调度器运行时需要的核心全局状态,比如 Goroutine 的运行队列、空闲 M/P 的缓存、统计信息、定时器、安全点、垃圾回收(GC)的协调状态等等。
type schedt struct { | |
goidgen atomic.Uint64 | |
lastpoll atomic.Int64 | |
pollUntil atomic.Int64 | |
lock mutex | |
midle muintptr | |
nmidle int32 | |
nmidlelocked int32 | |
mnext int64 | |
maxmcount int32 | |
nmsys int32 | |
nmfreed int64 | |
ngsys atomic.Int32 | |
pidle puintptr | |
npidle atomic.Int32 | |
nmspinning atomic.Int32 | |
needspinning atomic.Uint32 | |
runq gQueue | |
runqsize int32 | |
disable struct { | |
user bool | |
runnable gQueue | |
n int32 | |
} | |
gFree struct { | |
lock mutex | |
stack gList | |
noStack gList | |
n int32 | |
} | |
sudoglock mutex | |
sudogcache *sudog | |
deferlock mutex | |
deferpool *_defer | |
freem *m | |
gcwaiting atomic.Bool | |
stopwait int32 | |
stopnote note | |
sysmonwait atomic.Bool | |
sysmonnote note | |
safePointFn func(*p) | |
safePointWait int32 | |
safePointNote note | |
profilehz int32 | |
procresizetime int64 | |
totaltime int64 | |
sysmonlock mutex | |
timeToRun timeHistogram | |
idleTime atomic.Int64 | |
totalMutexWaitTime atomic.Int64 | |
} |