• Golang goroutine MPG模式浅析


    goroutine-快速入门


    快速入门小结:
    (1)主线程是一个物理线程,直接作用在cpu上的。是重量级的,非常耗费cpu资源。
    (2)协程从主线程开局的,是轻量级的线程,是逻辑态,对资源消耗相对小。
    (3)Golang的协程机制是重要的特点,可以轻松的开启上万个协程。其它编程语言的并发机制是一般基于线程的,开启过多的线程,资源耗费大,这里就突显Golang在并发上的优势了

    协程是通过使用关键字 go 调用(或执行)一个函数或者方法来实现的(也可以是匿名函数)。

     Go 语言在语言层面上支持了并发,goroutine是Go语言提供的一种用户态线程,有时我们也称之为协程。

    所谓的协程,某种程度上也可以叫做轻量线程,它不由os而由应用程序创建和管理,因此使用开销较低(一般为4K)。

    我们可以创建很多的goroutine,并且它们跑在同一个内核线程之上的时候,就需要一个调度器来维护这些goroutine,确保所有的goroutine都能使用cpu,并且是尽可能公平地使用cpu资源。

    调度器的主要有4个重要部分,分别是M、G、P、Sched,前三个定义在runtime.h中,Sched定义在proc.c中。

    • M (work thread) 代表了系统线程OS Thread,由操作系统管理。

    • P (processor) 衔接M和G的调度上下文它负责将等待执行的G与M对接。P的数量可以通过GOMAXPROCS()来设置,它其实也就代表了真正的并发度,即有多少个goroutine可以同时运行。

    • G (goroutine) goroutine的实体,包括了调用栈,重要的调度信息,例如channel等。

    在操作系统的OS Thread和编程语言的User Thread之间,实际上存在3种线程对应模型,也就是:1:1,1:N,M:N。

    • N:1      多个(N)用户线程始终在一个内核线程上跑,context上下文切换很快,但是无法真正的利用多核。
    • 1:1      一个用户线程就只在一个内核线程上跑,这时可以利用多核,但是上下文切换很慢,切换效率很低。
    • M:N      多个goroutine在多个内核线程上跑,这个可以集齐上面两者的优势,但是无疑增加了调度的难度。

    M:N 综合两种方式(N:1,1:1)的优势。多个 goroutines 可以在多个 OS threads 上处理。既能快速切换上下文,也能利用多核的优势,而Go正是选择这种实现方式。

    MPG是其调度模型


    M:可以理解为主线程,它是一个物理级别的线程,它比较耗费资源。

    p:可以理解为在整个执行过程当中的上下文环境,上下文环境可以简单理解为运行时候所需要的资源或者当时操作系统的一个状态。

    在主线程运行的过程当中,启动了一个协程,在协程起来的时候需要有一个上下文的环境。上下文环境就是是否cpu可分配,需要的资源和当时运行的状态。

    G:是协程

    多个m作用在一个cpu,那么就是并发,作用在多个cpu就是并行。可以看到M可以开启多个协程,形成一个队列。

    Go 语言中的goroutine是运行在多核CPU中的(通过runtime.GOMAXPROCS(1)设定CPU核数)。 实际中运行的CPU核数未必会和实际物理CPU数相吻合。

    每个goroutine都会被一个特定的P(某个CPU)选定维护,而M(物理计算资源)每次挑选一个有效P,然后执行P中的goroutine。

    每个P会将自己所维护的goroutine放到一个G队列中,其中就包括了goroutine堆栈信息,是否可执行信息等等。

    底层可能维护了线程池,线程池里面可能预留了M1,也可能没有。这个就和操作系统底层相关了,如果有就将M1拿出来并且唤醒他,让其工作,如果没有那么就创建。

    这里创建的M1线程可能就在其他cpu上了,有点像并行。

    协程可以运行在操作系统多个线程之间,也可以运行在线程之内,让你可以很小的内存占用就可以处理大量的任务。由于操作系统线程上的协程时间片,你可以使用少量的操作系统线程就能拥有任意多个提供服务的协程,而且 Go 运行时可以聪明的意识到哪些协程被阻塞了,暂时搁置它们并处理其他协程。

    MPG并发模型 

     

    总结


    M代表主线程向下执行,p上下文可以根据系统情况开启协程去工作。M可能有很多,可能全部在一个CPU上面,也可能每个M都在各个不同的CPU上面,这样就叫做并行。

    当有协程被阻塞的时候,它有来回切换的一种机制,可以保证主线程的执行,也能够让排队的G协程得到执行的机会。

  • 相关阅读:
    非递归中序遍历二叉树
    网页数据抓取:融合BeautifulSoup和Scrapy的高级爬虫技术
    WEB静态网页设计与制作——我的美丽家乡邢台
    如何让你的.NET WebAPI程序支持HTTP3?
    idea debug 重启弹窗提示窗口询问是否关闭运行着的服务器
    卷积网络知识--深度可分离卷积
    【ZYNQ】IP核_DDR4_SDRAM(MIG)的详细介绍
    生活随笔-吐槽篇
    四、Vue3基础四
    快速打开命令行方法集合
  • 原文地址:https://blog.csdn.net/qq_34556414/article/details/132885357