Golang---GMP调度策略
Posted zpcoding
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang---GMP调度策略相关的知识,希望对你有一定的参考价值。
摘要:Go 能很好的支持并发模型,这也是 Go 如此火热的原因,那今天我们来学习 Go 的调度机制。
数据结构
G 结构体
G 是 goroutine 的缩写,相当于操作系统中的进程控制块,在这里就是 goroutine 的控制结构,是对 goroutine 的抽象,下面是 G 的结构(只列出了部分与调度有关的):
//用于保存上下文的 gobuf 结构体 type gobuf struct { sp uintptr //栈指针,上下文中的 sp 指针 pc uintptr //程序计数器,上下文中的 pc 指针 g guintptr //指向当前 g 的指针 ... } //用于表示一个等待链表上的 goroutine type sudog struct { g *g //阻塞列表上的 G next *sudog //双向链表后指针 prev *sudog //双向链表前指针 elem unsafe.Pointer //该 goroutine 的数据指针 c *hchan ... }
下面是 G 结构体:
type g struct { stack stack // offset known to runtime/cgo m *m // current m; offset known to arm liblink sched gobuf //进程切换时,利用 sched 来保存上下文 param unsafe.Pointer // 用于传递参数,睡眠时其它 goroutine 设置 param, 唤醒时此 goroutine 可以获取到 goid int64 //goroutine 的 ID号 lockedm muintptr //G 被锁定只能在这个 m 上运行 gopc uintptr //创建这个goroutine 的go 表达式的 pc waiting *sudog //这个 g 当前正在阻塞的 sudog 结构体 }
M 结构体
M 是 machine 的缩写,是对机器的抽象,每个 m 都是对应到一条操作系统的物理线程。M 必须关联了 P 才可以执行 Go 代码,但是当它处理阻塞或者系统调用中时,可以不需要关联 P。
type m struct { g0 *g // 带有调度栈的 goroutine(默认开启一个进程的时候会开启一个线程,又称主线程(g0)) mstartfn func() //执行函数体的 curg *g //当前运行的 goroutine p puintptr //为了执行 Go 代码而获取的 p(如果不需要执行 Go 代码(syscall...),可为 nil) id int64 //M 的 ID locks int32 park note alllink *m //用于链接 allm(一个全局变量) schedlink muintptr lockedg guintptr //某些情况下,goroutine 锁定到当前 m, 而不会到切换到其它 m 中去 createstack [32]uintptr // stack that created this thread. nextwaitm muintptr //期望获取锁的下一个 m syscall libcall //存储系统调用的参数 }
P 结构体
P 是 Processor 的缩写。结构体 P 的加入是为了提高 Go 程序的并发度。一共有 GOMAXPROCS(一般为 CPU 的核数) 个 P, 所有的 P 被组织成一个数组(allp), 在 P 上实现了工作流窃取的调度器。
type p struct { id int32 status uint32 //P 状态 pidle/prunning/... link puintptr schedtick uint32 // 每次执行 goroutine 调度 +1 syscalltick uint32 // 每次执行系统调用 +1 sysmontick sysmontick // last tick observed by sysmon m muintptr // 链接到它的 m (nil if idle) mcache *mcache pcache pageCache // Queue of runnable goroutines. Accessed without lock. // P 执行 Go 代码时,优先从自己这个局部队列中取,这时可以不用加锁,提高了并发度 // 如果发现这个队列是空,则去其它 P 的队列中拿一半过来,实现工作流窃取的调度,这种情况需要给调度器加锁 runqhead uint32 //本地 G 队列头 runqtail uint32 //本地 G 队列尾 runq [256]guintptr //本地 G 队列 runnext guintptr //下一个准备好运行的 goroutine sudogcache []*sudog sudogbuf [128]*sudog ... }
全局变量
调度策略
源码分析
总结
参考文献
以上是关于Golang---GMP调度策略的主要内容,如果未能解决你的问题,请参考以下文章
Linux 内核线程调度示例一 ② ( 获取指定调度策略的最大和最小优先级 | 代码示例 )
Linux 内核线程调度示例一 ③ ( 获取线程优先级 | 设置线程调度策略 | 代码示例 )
MATLAB代码:基于多智能体系统一致性算法的电力系统分布式经济调度策略
Linux 内核进程优先级与调度策略 ② ( 获取调度策略对应的进程优先级函数 | sched_get_priority_max 函数 | sched_get_priority_min 函数 )