Go线程实现模型-P

P

概述

P是G能够在M中运行关键。Go的运行时系统会适时地让P与不同的M建立或断开关联,以使P中的那些可运行的G能够及时获得,这与操作系统内核在CPU之上实时切换不同进程或线程的情况类似

改变P的数量

改变单个Go程序间拥有的P的最大数量有两种方法

  • 调用函数runtime.GoMAXRPOCS并把想要设定的数量作为参数传入
  • 在Go程序运行前设置环境变量GOMAXPROCS的值(硬性上限值256)

P的最大数量实际上是对程序中并发运行的G的规模的现实。P的数量即为可运行G的队列的数量。

一个G在被启用后,会先被追加到某个P的可运行G队列中,以等待时机。一个P只有与一个M关联在一起,才会使其可运行G队列中的G有机会运行

不过,设置P的最大数量只能限制住P的数量,而对G和M的数量没有任何约束。

使用了runtime.GoMAXRPOCS后,会暂时使P都脱离运行状态,并试图阻止任何用户级别的G的运行。只有在新P最大值设定完成后,运行时系统才会开始陆续恢复它们

M阻塞时,P的状况

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

这时,如果这个P的可运行G队列中还没有未被运行的G,那么运行时系统就会找到一个空闲M,或创建一个新的M,并与该P关联以满足这些G的运行需要

因此,M的数量在很多时候也都会比P多。而G的数量,一般取决于Go程序本身

重整P

在确定P最大数量之后,运行时系统会根据这个数值重整全局的P列表(runtime.allp)。与全局M列表类似,该列表中包含了当前运行时系统创建的所有P

运行时系统会把这些P中的可运行G全部取出,并放入调度器的可运行G队列中。被转移的那些G,会在以后经由调度再次放入某个P的可运行G队列

空闲P列表

与空闲M列表类似,运行时系统中也存在一个调度器的空闲P列表(runtime.sched.pidle)。当一个P不再与任何M关联的时候,运行时系统会把放入该列表

而当运行时系统需要一个空闲的P关联某个M的话,会从此列表中取出一个。注意,P进入空闲P列表的一个前提是它的可运行G列表必须为空

例如,在重整全局P列表的时候,P在被清空可运行G队列之后,才会被放入空闲P列表

P的状态转换

P的状态

Pidle: 此状态表明当前P未与任何M存在关联

Prunning: 此状态表明当前P正在与某个M关联

Psyscall: 此状态表明当前P中的运行的那个G正在进行系统调用

Pgcstop: 此状态表明运行时系统需要停止调度。例如运行时系统在开始垃圾回收的某些步骤前,就会试图把全局P列表中的所有P都置于这个状态

状态转换

P 创建之初的状态是Pgcstop,虽然这并不意味这时进行垃圾回收。不过,P处于这一初始状态的时间非常短暂

初始化之后,运行时系统会将其状态设置为pidle,并放入调度器的空闲P列表

图中可见,非Pdead状态的P都会在运行时系统欲停止调度时被置于Pgcstop状态,然后统一转换为Pidle状态,并公平地接受再次调度

另一方面,非Pgcstop状态的P都可能因全局P列表的缩小而被认为是多余的,并被置于Pdead状态。同时P被转换为Pdead前,其可运行G队列的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列表也弹尽粮绝的时,才会有新的G被创建。这在很大程度上提高了G的复用率

总结

在P的结构中,可运行G队列和自由G列表最重要的两个成员。至少对于Go语言的是这样,它们间接地体现了运行时系统对G的调度情况

相关推荐
system_error_x4 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
酷炫码神4 小时前
Day 10|Pinia 状态管理:把散落在各组件的数据,收进一个全局仓库
android·开发语言·javascript
microrain4 小时前
SagooIoT 的缓存换后端只改一行配置,文件后端连 Redis 都不需要
物联网·缓存·golang·sagooiot
驭渊的小故事5 小时前
Spring AI Alibaba 实战:从maven依赖治理到声明式工具调用
java·人工智能·spring
Elastic 中国社区官方博客5 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1885 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn6 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
y1su6 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
喵了几个咪6 小时前
GoWind ShortPlay 深度拆解:三服务 BFF + Core,一条请求的完整工程链路
golang·gowind
传奇开心果编程6 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用