Golang GMP原理(1)

Golang GMP原理(1)

概念梳理

线程

线程一般指内核级线程,核心如下:

  1. 操作系统的最小调度单元
  2. 创建 销毁 调度由内核完成,cpu要完成内核态与用户态的转换
  3. 可充分利用多核,实现并行

协程

协程线程对应

协程,又称为用户级线程,核心点如下:

  1. 与线程存在映射关系,为M:1
  2. 创建、销毁、调度在用户态完成,对内核透明,所以更轻
  3. 从属同一个内核级线程,无法并行;一个协程阻塞会导致从属同一线程的所有协程无法执行。

Goroutine

Goroutine是特殊的协程

  1. 与线程存在映射关系,为M:N
  2. 创建、销毁、调度在用户态完成,对内核透明,足够轻便
  3. 可利用多个线程实现并行
  4. 通过调度器实现和线程间的动态绑定和调度
  5. 栈空间可动态扩缩。

对比

模型 弱依赖内核 可并行 可应对阻塞 栈可动态扩缩
线程 × ×
协程 × × ×
goroutine

GMP模型

g

  1. g是goroutine,是对协程的抽象
  2. g有自己的运行栈、状态、以及执行的任务函数(用户通过go func指定)
  3. g需要绑定到p才能执行,在g的视角中,p是它的cpu

p

  1. p是调度器,联系g与m
  2. p的数量决定了g最大并行数量,可由用户通过GOMAXPROCS进行设定(超过CPU核数无意义)

m

  1. m是machine 是go中线程的抽象
  2. m不直接执行g,而是先和p绑定,由其实现代理
  3. 借由p的存在,m无需和g绑死,也无需记录g的状态信息,因此g在全生命周期中可实现跨m执行

gmp

  1. m是线程的抽象 g是goroutine p'是调度器
  2. m调度g前 需要和p绑定
  3. 全局有多个m和p 同时并行的g最大数量等于p的数量
  4. g的存放队列有三类:P的本地队列;全局队列;和wait队列(图中未展示,为io阻塞就绪态goroutine队列)
  5. m调度g时,优先取p本地队列,其次取全局队列,最后取wait队列;这样的好处是,取本地队列时,可以接近于无锁化,减少全局锁竞争;
  6. 为防止不同p的闲忙差异过大,设立work-stealing机制,本地队列为空的p可以尝试从其他p本地队列偷取一半的g补充到自身队列.

热门相关:首席的独宠新娘   夫人,你马甲又掉了!   名门天后:重生国民千金   学霸女神超给力   最强装逼打脸系统