本文源码版本基于 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 
)

img

# 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
)

img

# 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 
}