前序

正确地认识 G , M , P 三者的关系,能够对协程的调度机制有更深入的理解! 本文将会完整介绍完 go 协程的调度机制,包含:

  • 调度对象的主要组成
  • 各对象的关系 与 分工
  • gorutine 协程是如何被执行的
  • 内核线程 sysmon 对 gorutine 的管理
  • gorutine 协程中断挂起 与 恢复
  • GOMAXPROCS 如何影响 go 的并发性能

调度器的三个基本对象:

协程(goroutine)线程(Thread)
go 关键词处理器

G-M-P三者的关系与特点:

队列队列中GOMAXPROCS

image

局部G队列与全局G队列的关系

协程任务全局队列

Gorutine从入队到执行

gorutine空队列一个点底层线程循环执行

解答问题-①

中断,挂起

原理:

sysmon
计数 schedtickschedtick非内联函数
hello world
func main(){
    runtime.GOMAXPROCS(1)
    go func(){
        fmt.Println("hello world")
        // panic("hello world")  // 强制观察输出
    }()
    go func(){
        for {
            // fmt.Println("aaa")  // 非内联函数,这行注释打开,将导致 hello world 的输出
        }
    }()
    select {}
}

中断后的恢复

  1. 中断的时候将寄存器里的栈信息,保存到自己的 G 对象里面
  2. 当再次轮到自己执行时,将自己保存的栈信息复制到寄存器里面,这样就接着上次之后运

GOMAXPROCS--性能调优

GOMAXPROCS

故,我们一般将 GOMAXPROCS 的个数设置为 CPU 的核数,且需要注意的是:

  • go 1.5 版本之前的 GOMAXPROCS 默认是 1
  • go 1.5 版本之后的 GOMAXPROCS 默认是 Num of cpu