作者:林冠宏 / 指尖下的幽灵
掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8
博客:http://www.cnblogs.com/linguanh/
GitHub : https://github.com/af913337456/
腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities
正确地认识 G , M , P 三者的关系,能够对协程的调度机制有更深入的理解! 本文将会完整介绍完 go 协程的调度机制,包含:
Golang 简称 Go,Go 的协程(goroutine)
和我们常见的线程(Thread)
一样,拥有其调度器。
go 关键词
时候会创建的一个对象处理器
,又称上下文队列
队列中
提取 G,并执行GOMAXPROCS
(最大256),启动时固定的,一般不修改协程任务
交换全局队列
找gorutine
,它会加入到本地队列或者全局队列空队列
一个点
! 底层线程
,循环执行
能找到的 G 任务。这里的寻找的 G 从下面几方面找: 协程的切换时间片是10ms,也就是说 goroutine 最多执行10ms就会被 M 切换到下一个 G。这个过程,又被称为 中断,挂起
原理:
go程序启动时会首先创建一个特殊的内核线程 sysmon
,用来监控和管理,其内部是一个循环:
计数 schedtick
,schedtick会在每执行一个G任务后递增schedtick
一直没有递增,说明这个 P 一直在执行同一个 G 任务,如果超过10ms,就在这个G任务的栈信息里面加一个 tag 标记非内联函数
调用的话,那就会一直执行这个G任务,直到它自己结束;如果是个死循环,并且 GOMAXPROCS=1 的话。那么一直只会只有一个 P 与一个 M,且队列中的其他 G 不会被执行!例子,下面的这段代码,hello world
不会被输出
func main(){
runtime.GOMAXPROCS(1)
go func(){
fmt.Println("hello world")
}()
go func(){
for {
}
}()
select {}
}
看完上面的内容,相信你已经知道,GOMAXPROCS
就是 go 中 runtime 包的一个函数。它设置了 P 的最多的个数。这也就直接导致了 M 最多的个数是多少,而 M 的个数就决定了各个 G 队列能同时被多少个 M 线程来进行调取执行!
故,我们一般将 GOMAXPROCS 的个数设置为 CPU 的核数,且需要注意的是: