分享
  1. 首页
  2. 文章

Golang协程调度的数据结构

丁凯 · · 2063 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Golang中实现协程调度算法的主要有以下三个数据结构,正是这三个结构加上一些算法构成了Golang的协程调度算法,当然,这些数据结构也是在不断进化的,保不准未来又会加入其他结构来提升调度器性能。

协程调度主要数据结构

其中:

M: 代表操作系统线程,也就是我们经常理解的线程,是真正参与OS调度的单元,每个goroutine只有依附于某个M方可真正地执行;
G: 代表协程,也就是我们经常使用的Goroutine;
P: 协程调度器的基本调度单元,G的容身之所,连接G和M的桥梁。

理解调度器的关键是理解P的作用:它是实现M:N调度的关键结构。在Golang1.1版本中被引入,解决了1.0中的全局调度队列带来的可扩展性问题。

三个数据结构之间的关系如下:

  • 每个G都必须依附于某个P;
  • 每个M想运行的时候,必须先获取一个P,再执行P中的G;
  • 每个P维护可运行G队列,避免了全局G队列带来的锁竞争问题,提高了调度器的可扩展性;
  • 如果一个M在执行G的时候进入了syscall,那么该M就被占据了,与其关联的P此时就游离出来,可被同样处于idle状态的M获取到,进而P内的G得到继续执行的机会;
  • go中可通过GOMAXPROCS()来设置P的数量,一般建议设置成系统核数即可,P的数量也代表了当前活跃的M数(因进入syscall而block的M不计算在内)。
struct G {
 ......
 m *m
}
struct M {
 ......
 G* curg; // current running goroutine 
 P* p; // attached P for executing Go code (nil if not executing Go code) 
 ......
}
struct P {
 ......
 M* m; // back-link to associated M (nil if idle) 
 ......
 // Queue of runnable goroutines. 
 uint32 runqhead;
 uint32 runqtail;
 G* runq[256];
 // Available G's (status == Gdead) 
 G* gfree;
 ......
};

阅读上面的数据结构可发现他们三者之间的关系是这样的:

  • g:有一个指针指向执行它的m,也即g隶属于m;
  • m:保存了当前正在执行的g,同时还指向p,也即m隶属于p;
  • p: 保存了当前正执行p内g的m,同时还有属于它的g的链表

有疑问加站长微信联系(非本文作者)

本文来自:知乎专栏

感谢作者:丁凯

查看原文:Golang协程调度的数据结构

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2063 次点击
被以下专栏收入,发现更多相似内容
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏