go concurrency

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

Do not communicate by sharing memory; instead, share memory by communicating

GMP

G

  • G即 Goroutine, 它包括堆栈、指令指针和其他对调度goroutines很重要的信息
  • go不同版本Goroutine默认栈大小不同
  • 线程是运行Goroutine的实体, 调度器的功能是把可以运行的Goroutine分配到工作线程上

M

  • M即工作线程,所有M都是有线程栈的, 每个M代表了1个内核线程.OS调度器负责把内核线程分配到CPU的核上运行
  • M必须和P关联才能运行G
  • work stealing: 当M绑定的P没有可运行的G时,它可以从其他运行的M那里偷取G
  • 线程想要运行任务需要获取P, 从P的本地队列获取G,
  • P本地队列为空时, M也会尝试从全局队列获取一批G放到本地P的本地队列
  • 或从其他P的本地队列偷一般放到自己P的本地队列
  • M运行G, G执行之后, M会从P获取下一个G, 不断重复下去

P

  • P即Processor是一个抽象的概念, 并不是真正的物理CPU, 它包含了运行Goroutine的资源
  • 线程想运行G, 必须先获取P, P中包含了可运行的G队列
  • P需要和M进行绑定, 构成一个执行单元
  • P决定了同时可以并发任务的数量

通过runtime.GOMAXPROCS限制同时执行用户级任务的操作系统线程, Go1.5以后被设置可用的核数

  • P有两种队列
    1. 本地队列

    当前P的队列,本地队列是Lock-Free,没有数据竞争问题,无需加锁处理,可以提升处理速度。
    存放的也是等待运行的G,存的数量有限

    1. 全局队列

    全局队列为了保证多个P之间任务的平衡。所有M共享P全局队列,
    为保证数据竞争问题,需要加锁处理。相比本地队列,处理速度要低

GMP调度过程

gpm.png
  1. 正常情况下, 每个P(context)都会有local runqueue, 挂载若干的G, 其中只有一个G正在M上运行

  2. 每个P除了local runqueue, 所有的P还共享一个全局的global runqueue, 在某些情况下会将G挂载到这个global runqueue下,

  3. 当一个G系统阻塞了, 比如(调用了sleep或者I/O系统调用), G处于_Gsyscall状态,M也处于 block on syscall 状态,此时的M可被抢占调度,
    由于线程不能同时执行代码和被阻塞在syscall上,所以我们需要传递上下文,以便它能够继续调度
    go runtime却不会让对应的P(context)被阻塞(想一下,P的local runqueue下此时可能还挂了一串而goroutine呢) 而是去线程缓存池(M cached pool)中Get一个M出来如下图M1,把自己挂上去,从local runqueue上pop一个G出来继续执行;如果没有其它idle的M,但P的Local队列中仍然有G需要执行,则创建一个新的线程,并将P与之绑定,顺序执行P中下一个G.


    syscall.jpg
  4. 上一步中,P带着自己的local runqueue 跑路了,扔下M被阻塞,但是当时触发阻塞的G却并不会跟着P一起跑路,(G是一个比较厚道的人);

  5. M终于从blocked(e.g. I/O syscall)中返回了,此时想要继续执行这个G,但那是不可能的,因为G必须在P这个context下执行,所以这个M就去找空闲的P了,如果找到了,就把这个G挂上去开始执行,如果找不到,就把G加入到global runqueue(3中提到过,记得么?)中,而自己则很乖地去线程池报道(4中会用到);

  6. 为了避免global runqueue出现工地悲剧,每个P会时不时地去看下global runqueue是不是有G,避免这些G被饿死;(恩,大家都很nice呢);

  7. 当某个M-P下已经没有G的时候,P就会难掩助人为乐的精神,随机地跑到其它P下偷一半的G过来自己执行( 如下图)

  8. 当通过go关键字创建一个新的goroutine的时候,它会优先被放入P的本地队列。


    in-motion.jpg

Stealing work

steal.jpg

参考文献:


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

本文来自:简书

感谢作者:aside section ._1OhGeD

查看原文:go concurrency

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

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