Go线程实现模型-主框架、M

主框架

组件简述

M: machine的缩写。一个M代表一个内核线程,或称"工作线程"

P: processor的缩写。一个P代表执行一个Go代码片段所必需的资源(或称"上下文环境")

G: goroutine的缩写。一个G代表一个GO代码片段。前者是对后者的一种封装

组件功能简述

一个G的执行需要P和M的支持。一个M在与一个P关联之后,就形成了一个有效的G运行环境(内核线程+上下文环境)

每个P都会包含一个可运行的G的队列(runq)。该队列中的G会依次传递给与本地P关联的M,并获取运行时机

可以看到,M与KSE之间总是一对一的关系,一个M能且仅能代表一个内核线程

Go的运行时系统(runtime system)用M代表一个内核调度实体。M与KSE之间的关联非常稳固,一个M在其生命周期内,会且仅会与一个KSE产生关联

相比之下,M与P、P与G之间的关联是易变的,它们之间的关系会在实际调度的过程中改变

  • 其中,M与P之间也总是一对一的,而P与G之间也会建立关联
  • 因为一个G终归会由一个M来负责运行,它们之间的关联会由P来牵线

M

概述

一个M代表了一个内核线程。在大多数情况下,创建一个M,都是由于没有足够的M来关联P并运行其中可运行的G

不过,在运行时系统执行系统监控或垃圾回收等任务的时候,也会导致新M的创建

M的结构

g0: 表示一个特殊goroutine。这个goroutime是Go运行时系统在启动之初创建的,用于执行一些运行时任务

mstartfn: 表示M的起始函数,这个函数其实就是在编写go语句时携带的那个函数

curg: 表示存放当前M正在运行的那个G的指针

p: 表示与当前M相关联的那个P

nextp: 表示与当前M有潜在关联的P。把调度器将某个P赋给某个M的nextp字段操作,称为对M和P的预联。运行时系统有时候会把刚重新启动的M和已与它预联的那个P关联在一起,这也是nextp字段的主要作用

spinning: bool类型的,它用于表示这个M是否正在寻找可运行的G。在寻找过程中,M会处于自旋状态。Go运行时系统可以把一个M和一个G锁定在一起,一旦锁定,这个M就只能运行这个G,这个G也只能由该M运行

M的运行

基础的运行

M在创建之初,会被加入全局的M列表(runtime.allm)中。这时,它的起始函数和预联的P也会被设置

最后,运行时系统会为这个M专门创建一个新的内核线程并与之相关联。

如此一来,这个M就为执行G做好了准备。其中,起始函数仅当运行时候系统要用此M执行系统监控或垃圾回收等任务的时候才会被设置

这里的全局M列表其实并没有什么特殊的意义。运行时系统在需要的时候,会通过它获取所有M的信息。同时,它也可以防止M被当作垃圾回收掉

M的优化

在新M被创建之后,Go运行时系统会对它进行一番初始化,其中包括对自身所持的栈空间以及信号处理方面的初始化

在这个初始化工作都完成之后,该M的起始函数会执行。注意,如果这个起始函数代表的是系统监控任务,那么该M会一直执行下去,而不会继续后面的流程

否则,在起始函数执行完毕之后,当前M将会与那个预联的P完成关联,并准备执行其他任务。M会依次在多处寻找可运行的G并运行之。有了M,Go程序的并发运行基础才得以形成

M的空闲时的状态

运行时系统管辖的M(runtime.allm中的M)有时候也会被停止,比如在运行时系统执行垃圾回收任务过程中

运行时系统在停止M的时候,会把它放入调度器的空闲M列表(runtime.sched.midle)。这很重要,因为在需要一个未被使用的M时,运行时系统会先尝试从该列表中获取

M是否空闲,仅以它是否存在于调度器的空闲M列表中为依据

M的数量设置

单个Go程序所使用的M的最大数量是可以设置的。Go程序运行时候会启动一个引导程序,这个引导程序会为其运行建立必要的环境

在初始化调度器的时候,它会对M的最大数量进行初始设置,这个初始值是10000.也就是说,一个Go程序最多可以使用10000个M

  • 这意味着,最多可以有10000个内核线程服务于当前的Go程序

可以调用标准库代码包runtime/debug中的SetMaxThreads函数,并提供新的M的最大数量

runtime/debug.SetMaxThreads函数在执行完成后,会把旧的M最大数量作为结果值返回

相关推荐
wdfk_prog29 分钟前
[Linux]学习笔记系列 -- hashtable
linux·笔记·学习
期待のcode42 分钟前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐1 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
a程序小傲1 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红1 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥1 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring
CheungChunChiu1 小时前
Linux 内核动态打印机制详解
android·linux·服务器·前端·ubuntu
小楼v1 小时前
说说常见的限流算法及如何使用Redisson实现多机限流
java·后端·redisson·限流算法
与遨游于天地1 小时前
NIO的三个组件解决三个问题
java·后端·nio
czlczl200209252 小时前
Guava Cache 原理与实战
java·后端·spring