美文网首页Go
Go协程介绍

Go协程介绍

作者: Dakini_Wind | 来源:发表于2021-04-21 20:26 被阅读0次

    参考自《go专家编程》
    Go协程所实现的是M:N的线程模型,M个协程运行在N个线程中。

    1. MPG模型

    Go协程中有三个关键实体:

    • M(machine): 工作线程,由操作系统调度。应该就是通常所说的内核线程。
    • P(processor): 处理器(非CPU),代表着运行Go代码的必要资源,以及调度goroutine的能力。个人觉得可以当作拥有自主调度权的算法模块,用于工作窃取(work stealing)
    • G(gooutine): Go协程,轻量级用户线程。主要包含执行栈调度管理器。这里的调度管理器指的是,统一并管理调度资源,等待被调度。

    其关系如下图:

    MPG模型图.png

    关于M的数目:
    M的个数是根据实际情况自行创建的,一般稍大于P的个数,为了保证runtime包的内置任务的运行。在运行中不够用时,也会再重新创建一个。
    关于P的数目:
    P的个数默认为CPU的核数,在IO密集的场景下可以适当提高P的个数。设置方式有两种,例:
    设置环境变量:

    export GOMAXPROCS=80
    

    runtime.GOMAXPROCS()方法:

    runtime.GOMAXPROCS(80)
    
    • 全局runqueue队列

    全局队列由多个处理器共享,访问通过互斥锁来完成。
    处理器P中的协程G额外再创建的协程会加入到本地的runqueues中。
    两种情况下会放入全局队列中:1. 本地队列已满 2. 阻塞的协程被唤醒
    全局队列会被处理器P周期性的摘取来调度。

    2. 调度策略

    • 队列轮转

    每个处理器P维护着一个协程G的队列,处理器依次将协程G调度到M中执行。
    此外,每个 P周期性的查看全局队列中是否有G将其调度到M中执行。
    (全局队列中的G主要来自系统调用中恢复的G。)

    • 系统调用

    前情提要:1.如一个线程进行系统调用会进入阻塞状态,一个协程进行系统调用也会导致线程进入阻塞状态。2. 前面提到M的数量会稍大于P的数量,多出来的M在系统调用时就会发挥作用。3. 当M不够用时,会再创建M

    M0运行的G0产生系统调用时,M0将会释放P,进而某个冗余的M1将会获取P,继而执行P中所剩下的G。这时候M0进入阻塞,而M1接替M0的工作。

    所以,在开发中一定要避免频繁的系统调用!!!一旦调用结束的速度跟不上调用产生的速度,那么系统资源将会有严重的浪费!

    G0的系统调用结束后呢?
    此时根据M0是否能获取到P来对G0作出不同的处理:1. 如果有空闲的P,则获取继续执行G0。2. 如果没有空闲的P,将把G0放入全局队列,等待被其他的P调度。M0将进入缓存池。

    • 工作量窃取

    工作量窃取是为了实现P的负载均衡。
    当当前P没有协程调度,并且全局队列中也没有需要调度的协程时,会从另一个正在运行的处理器P中偷取协程,每次偷取一半。

    • 抢占式调度

    该机制是为了避免某个协程长时间执行,而阻碍到其他协程被调度。
    调度器监控每个协程的执行时间,当其执行时间过长且有其他协程在等待是,会把协程暂停,转而调度等待的协程,达到类似时间片轮转的效果。

    相关文章

      网友评论

        本文标题:Go协程介绍

        本文链接:https://www.haomeiwen.com/subject/epwzlltx.html