Golang GMP原理

Published on in Technology with 0 views and 0 comments
  • 1. 概念梳理

  • 1.1 线程

    • 通常指内核级线程,具有以下特点:·
      • 是操作系统的做小调度单元;
      • 创建,销毁,调度交由内核完成,cup需要完成用户态与内核态的切换;
      • 可充分利用多核,实现并行。
  • 1.2 协程

    • image.png
    • 协程:又称为用户级别线程,核心如下:
      • 与线程存在映射关系:M:1
      • 创建,销毁,调度在用户态完成,对内核透明
      • 从属同一个内核级线程,无法并行;一个协程阻塞会导致从属同一个线程的所有协程无法执行。
  • 1.3 Goroutine

    • image.png
    • Goroutine,经Golang优化后的特殊协程,核心点如下:
      • 与线程存在映射关系:M:N
      • 创建,销毁,调度在用户态完成,对内核透明
      • 可利用多个线程,实现并行。
      • 通过调度器的调度,实现和线程间的动态绑定和灵活调度;
      • 栈空间大小可动态扩缩,因地制宜。
    • image.png
    • 实际上,“灵活调度” 一词概括得实在过于简要,Golang 在调度 goroutine 时,针对“如何减少加锁行为”,“如何避免资源不均”等问题都给出了精彩的解决方案,这一切都得益于经典的 “gmp” 模型。
  • 2. GMP模型

  • GMP = goroutine+machine+processor+(一套有机组合的机制)

  • 2.1 G(Goroutine)

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

    • p 即 processor,是 golang 中的调度器;
    • p 是 gmp 的中枢,借由 p 承上启下,实现 g 和 m 之间的动态有机结合;
    • 对 g 而言,p 是其 cpu,g 只有被 p 调度,才得以执行;
    • 对 m 而言,p 是其执行代理,为其提供必要信息的同时(可执行的 g、内存分配情况等),并隐藏了繁杂的调度细节;
    • p 的数量决定了 g 最大并行数量,可由用户通过 GOMAXPROCS 进行设定(超过 CPU 核数时无意义).
  • 2.3 M

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

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

标题:Golang GMP原理
作者:wangzhaoo
地址:http://www.bangnimang.top/go-gmp