在go中,线程是运行Groutine的实体,调度器的功能是把可以运行的Groutine分配到工作线程上
GPM模型
M与P的数量没有绝对的数量关系,当一个M阻塞时,P就会创建一个或者切换到另一个M,所以即使设置了runtime.GOMAXPROCS(1)
也可能创建多个M出来;
当M发现给自己输送G协程的那个P队列为空时会主动从其他P队列"偷",这个过程的发起端是协程调度器,
当M阻塞时,P调度器会将令阻塞的M释放绑定的P,而后把这个P交给其他M区执行;
GPM模型为了更大程度地利用M和P的性能,不会让一个P永远被一个阻塞的G1耽误之后的工作
Go中,一个协程最多占用cpu10ms,这样是为了防止其他协程无cpu可用
协程的调度流程
Go中堆栈跟踪器
func main() {
file, err := os.Create("trackSpace.out")
if err != nil {
log.Println(err)
}
defer file.Close()
//将对战信息输出到文件中
err = trace.Start(file)
if err != nil {
log.Println(err)
}
defer trace.Stop()
fmt.Println("GMP-Stack")
}
这将会生成一个*.out文件,我们使用
go tool *.out
来分析一下堆栈信息:
PS D:\GolandData\ginlearn0906\src\hello> go tool trace .\trackSpace.out
2023/09/10 20:37:31 Parsing trace...
2023/09/10 20:37:31 Splitting trace...
2023/09/10 20:37:31 Opening browser. Trace viewer is listening on http://127.0.0.1:62208
我们可以看到每次运行时都会有一个G1协程—即main的协程(守护)
同时我们点击Goroutines会看到一个G0协程用于线程的初始化的时候使用;
未完待续