Go   发布时间:2022-04-09  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Golang 的 协程调度机制 与 GOMAXPROCS 性能调优大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

<h4 id="前序">前序@H_675_1@

Golang 简称 Go,Go 的协程(goroutInE) 和我们常见的线程(Thread)一样,拥有其调度器。@H_675_1@

  • G (GoroutInE),代表协程,也就是每次代码中使用 go 关键词时候会创建的一个对象
  • @H_837_5@m (Work Thread),工作线程
  • P (Processor),代表一个处理器,又称上下文

  • 一个运行的 M 都必须绑定一个 P,线程M 创建后会去检查并执行G (goroutInE)对象
  • 一个 P 保存着一个协程G 的队列
  • 除了每个 P 自身保存的 G 的队列外,调度器还拥有一个全局的 G 队列
  • @H_837_5@m队列中提取 G,并执行
  • P 的个数就是GOMAXPROCS(最大256),启动时固定的,一般不修改
  • @H_837_5@m 的个数和 P 的个数不一定一样多(会有休眠的M 或 P不绑定M )(最大10000)
  • P 是用一个全局数组(255)来保存的,并且维护着一个全局的 P 空闲链表

Golang 的 协程调度机制 与 GOMAXPROCS 性能调优@H_675_1@@H_675_1@@H_675_1@

  • 全局G任务队列会和各个本地G任务队列按照一定的策略互相交换。没错,就是协程任务交换
  • G任务的执行顺序是,先从本地队列找,本地没有则从全局队列
  • 转移
    • 局部与全局,全局G个数 / P个数
    • 局部与局部,一次性转移一半

  1. 我们创一个G对象,就是 goruTine,它会加入到本地队列或者全局队列
  2. 如果还有空闲的P,则创建@L_565_9@m 绑定该 P ,注意!这里,P 此前必须还没绑定过M 的,否则不满足空闲的条件。细节点:
    1. 先找到一个空闲的P,如果没有则直接返回
    2. P 个数不会占用超过自己设定的cpu个数
    3. P 在被 M 绑定后,就会初始化自己的 G 队列,此时是一个空队列
    4. 注意这里的一个
      • 无论在哪个 M 中创建了一个 G,只要 P 有空闲的,就会引起新 M 的创建
      • 不需虑当前所在 M 中所绑的 P 的 G 队列是否已满
      • 新创建的 M 所绑的 P 的初始化队列会从其他 G 队列中取任务过来
    5. 这里留下第一个问题:@H_675_1@

  3. @H_837_5@m 会启动一个底层线程循环执行能找到的 G 任务。这里的寻找的 G 从下面几方面找:
    • 当前 M 所绑的 P 队列中找
    • 去别的 P 的队列中找
    • 去全局 G 队列中找
  4. G任务的执行顺序是,先从本地队列找,本地没有则从全局队列找
  5. 程序启动的时候,首先跑的是主线程,然后这个主线程会绑定第一个 P
  6. 入口 main 函数,其实是作为一个 goroutIne 来执行

协程的切换时间片是10ms,也就是说 goroutIne 最多执行10ms就会被 M 切换到下一个 G。这个过程,又被称为 中断,挂起@H_675_1@

原理:@H_675_1@

go程序启动时会首先创建一个特殊的内核线程 sysmon,用来监控和管理,其内部是一个循环:@H_675_1@

  1. 记录所有 P 的 G 任务的计数 schedtickschedtick会在每执行一个G任务后递增@H_675_1@

  2. 如果检查到 schedtick 一直没有递增,说明这个 P 一直在执行一个 G 任务,如果超过10ms,就在这个G任务的栈信息里面加一个 tag 标记@H_675_1@

  3. 然后这个 G 任务在执行的时候,如果遇到非内联函数调用,就会检查一次这个标记,然后中断自己,把自己加到队列末尾,执行下一个G@H_675_1@

  4. 如果没有遇到非内联函数 调用的话,那就会一直执行这个G任务,直到它自己结束;如果是个死循环,并且 GOMAXPROCS=1 的话。那么一直只会只有一个 P 与一个 M,且队列中的其他 G 不会被执行!@H_675_1@

例子,下面的这段代码Hello world 不会被输出@H_675_1@


func main(){
    runtime.GOMAXPROCS(1)
    go func(){
        fmt.Println("Hello world")
    }()
    go func(){
        for {
    }
}()
SELEct {}

}
<h4 id="中断后的恢复">中断后的恢复

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

性能调优">GOMAXPROCS--性能调优

看完上面的内容,相信你已经知道,GOMAXPROCS 就是 go 中 runtime 包的一个函数。它设置了 P 的最多的个数。这也就直接导致了 M 最多的个数是多少,而 M 的个数就决定了各个 G 队列能同时被多少个 M 线程来进行调取执行!@H_675_1@

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

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

大佬总结

以上是大佬教程为你收集整理的Golang 的 协程调度机制 与 GOMAXPROCS 性能调优全部内容,希望文章能够帮你解决Golang 的 协程调度机制 与 GOMAXPROCS 性能调优所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: