文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Go语言中为什么要有GMP调度模型

2023-07-06 04:21

关注

今天小编给大家分享一下Go语言中为什么要有GMP调度模型的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

GMP调度模型是Go的精髓所在,它合理地解决了多线程并发调度协程的效率问题。

GMP是什么

首先得清楚,GMP各代指什么东西。

线程M各自持有一个处理器P,当要获取协程时优先从P中获取,于是GMP模型图解如下:

Go语言中为什么要有GMP调度模型

大致流程是,线程M从P的队列中获取协程,如果获取不到,就会从全局队列中去竞争锁来获取。

处理器P

协程G和线程M结构在前几篇已经讲解了,这里解析一下处理器P。

作用

处理器P储存着一批协程,使得线程M可以无锁的从中获取协程,而无需与其他线程去竞争全局队列中的协程,从而提高调度协程效率。

源码解析

p结构体源码在src\runtime\runtime2.go中,这里展示部分重要字段。

type p struct {   ...   m           muintptr   // back-link to associated m (nil if idle)   // Queue of runnable goroutines. Accessed without lock.   runqhead uint32   runqtail uint32   runq     [256]guintptr   runnext guintptr   ...}

Go语言中为什么要有GMP调度模型

线程M与处理器P是如何协作的?

src\runtime\proc.go中,有一个schedule方法,这是线程运行的第一个函数。这函数中,线程需要获取到可运行的协程,代码如下:

func schedule() {        ...    // 寻找一个可运行的协程    gp, inheritTime, tryWakeP := findRunnable()     ...}
func findRunnable() (gp *g, inheritTime, tryWakeP bool) {    // 从本地队列中获取协程    if gp, inheritTime := runqget(pp); gp != nil {       return gp, inheritTime, false    }    // 本地队列拿不到则从全局队列中获取协程    if sched.runqsize != 0 {       lock(&sched.lock)       gp := globrunqget(pp, 0)       unlock(&sched.lock)       if gp != nil {          return gp, false, false       }    }}

从本地队列中获取协程

func runqget(pp *p) (gp *g, inheritTime bool) {   next := pp.runnext // 队列中下一个可运行的协程   if next != 0 && pp.runnext.cas(next, 0) {      return next.ptr(), true   }   ...}

那如果本地队列和全局队列中都没有协程了怎么办呢,难道就让线程这么闲着?

这时候处理器P就会任务窃取,从其他线程的本地队列中窃取一些任务,美其名曰分担其他线程的压力,还提高了自己线程的利用率。

源码在src\runtime\proc.go\stealWork中,感兴趣可以看看。

新建的协程该分配到哪?

新建的协程该分配到本地还是全局队列呢,得分情况:

实际流程为:

  1. 随机寻找P

  2. 将新协程放入P的runnext中,意味着下一个就运行该协程,插队了

  3. 若P的协程满了,则放入全局队列

源码在src\runtime\proc.go\newproc函数中。

// Create a new g running fn.// Put it on the queue of g's waiting to run.// The compiler turns a go statement into a call to this.func newproc(fn *funcval) {   gp := getg()   pc := getcallerpc()   systemstack(func() {      newg := newproc1(fn, gp, pc) // 创建新协程      pp := getg().m.p.ptr()      runqput(pp, newg, true) // 寻找本地队列放入      if mainStarted {         wakep()      }   })}

以上就是“Go语言中为什么要有GMP调度模型”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯