go线程实现模型 MPG

88 篇文章 0 订阅

摘自:go并发编程实战 第二版

目录

核心元素

M

P

P的状态有如下:

G

M与P断开

创建M


核心元素

M

machine的缩写,一个M代表一个内核线程,或“工作线程”。在大多数情况下,创建一个M,都是由于没有足够的M来关联P并运行其中可运行的G。在运行时系统执行系统监控或垃圾回收等任务时,也会导致M的创建

M最大数量初始值是10000.

可以通过runtime/debug下的设置。如果真的需要设置M,那么越早调用该函数越好。

debug.SetMaxThreads()

P

processor的缩写。一个P代表执行一个Go代码片段所必须的资源(或称"上下文环境")。P是G能够在M中运行的关键,go的运行时系统会适时让P与不同的M建立或者断开关联,以使P中那些可运行的G能够及时获得运行时机,这与操作系统内核在cpu上实时的切换不同进程或者线程类似。

简单来说,一个G的执行需要P和M的支持。一个M在与一个P关联后,就形成了一个有效的G运行环节(内核线程+ 上下文环境)。每个P都会包含一个可运行的G的队列。该队列中的G会被依次传递给与本地P关联的M,并获得运行时机

 

由图4-2知,M与KSE之间总是一对一的关系,一个M能且仅能代表一个内核线程。go的运行时系统(runtime system)用M代表一个内核调度实体 。M与KSE之间的关联非常稳固,一个M在其生命周期内,会且仅会与一个KSE产生关联。相比之下,M与P、P与G之间的关联都易变,他们之间的关系会在实际调度过程中改变。其中,M与P之间也总是一对一的,而P与G之间则是一对多关系。此外,M与G也会建立关联,因为一个G终归会由一个M来负责运行,他们之间的关联由P来牵线。

改变单个go程序间接拥有的P的最大数量有两种办法。

1.调用系统的runtime.GOMAXPROCS并把想要设定的数量作为参数传入;

2.在go程序运行前设置环境变量GOMAXPROCS的值。

P的最大数量实际上是对程序中并发运行的G的规模的一种限制。P的数量即是可运行的G的队列的数量,一个G在被启用之后,会先被追加到某个P的可运行的G队列中,以等待运行时机。一个P只有与M相关联在一起,才会使其可运行G队列中的G有机会运行。不过,设置P的最大数量只能限制P的数量,而对G和M的数量没有任何约束。当M因系统调度而阻塞(确切的说,M运行的G进入了系统调用)的时候,运行时系统会把该M和与之关联的P分离开。这时,些G的运行如果这个P的可运行G队列中还有未被运行的G,那么运行时系统就会找一个空闲的M,或者创建一个新的M并与该P关联以满足这需要。因此M的数量很多时候都会比P多,而G的数量,取决于程序本身。

P的状态有如下:

1.pidle:当前P未与任何M存在关联

2.prunning:当前P正在与某个M关联

3.psyscall:当前P中的运行的那个G正在进行系统调用。如运行时系统在开始gc的某些步骤前,会试图把全局P列表中的所有P都置于这个状态。

4.pdead,当前P已经不会再被使用,如果在go程序运行的过程中,通过runtime.GOMAXPROCS的函数减少了P的最大数量,那么多余的P的数量就会被运行时系统置于该状态。

5.pgcstop:运行时系统需要停止调度

P在创建之初的状态是pgcstop,并不意味着运行时系统在这时进行gc。不过P处于这一初始状态的时间会很短暂,在紧接着的初始化后,运行时系统会将其状态置为pidle,并放入调度器的空闲P列表。

由图可见,非pdead状态的P都会在运行时系统停止调度时被置于pgcstop状态。等到需要重启调度的时候(如gc结束后),他们并不会被恢复至原有状态,而会被统一的转换为pidle。等待被再次调度。

非pgcstop状态的P都可能因全局P列表的缩小而被认为是多余的被置为pdead。此时不必担心其中的G会失去归宿,因为在P被转换为pdead状态之前,其可运行G队列中的G都会被转移到调度器的可运行G队列,而它的自由G列表中的G也都会被转移到调度器的自由G列表中。

每个P中除了都有一个可运行的G队列,还都包含一个自由G列表,这个列表中包含了一些已经运行完成的G。随着运行完成的G的增多,该列表可能会很大。当增长到一定成都,运行时系统就会把其中的部分G转移到调度器的自由G列表。

当使用go语句来启用一个G的时候,运行时系统会先试图从相应的P的自由G列表中获取一个现成的G,来封装这个go语句。当且仅当获取不到这样一个G的时候才会创建按一个新的G。如果P的自由G列表为空无法获取到自由G,运行时系统会在调度器的自由G列表中转移一些过来。

因此,只有当调度器的自由G列表为空的时候,才会有新的G被创建,提高了G的复用率。

在P的结构中,可运行G队列和自由G列表是最重要的成员。

G

goroutine的缩写。一个G代表一个Go代码片段。

一个goroutine的执行需要P和M的支持,一个M在与P关联后,就形成了一个有效的G运行环境(内核线程+上下文环境)。每个P都会包含一个可运行的G的队列,该队列的G会被依次传递给与本地P关联的M,并获得运行时机。

M与P断开

当M因系统调度而阻塞(确切的说,M运行的G进入了系统调用)的时候,运行时系统会把该M和与之关联的P分离开

创建M

1.没有足够的M来关联P并运行其中可运行的G。

2.在运行时系统执行系统监控或垃圾回收等任务时,也会导致M的创建。

 

go调度解析:https://studygolang.com/articles/15316

work-steal: https://rakyll.org/scheduler/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值