锁定g和m

在执⾏

锁定操作很简单,只需设置

lockedm 会休眠,直到某⼈将 lockedg 交给它。⽽不幸拿到 lockedg 的 M,

则要将

UnlockOSThread可主动解除锁定

 

 

系统调用

有两类系统调用:Syscall 和 RawSyscall

RawSyscall对应的系统调用都是非阻塞的,不需要runtime的参与,会立即返回,如果用RawSyscall去调用阻塞的系统调用,p将被浪费。

Syscall 增加了 entersyscall/exitsyscall,确保sysmon正常执行,sysmon会在系统调用长时间阻塞时,调度其他任务。有的系统调用一定会长时间阻塞,这些系统调用会执行entersyscallblock主动交出关联的p。退出系统调用的快速路径 exitsyscallfast 是指能重新绑定原有或空闲的 P,以继续当前 G 任务执⾏。如果多次尝试绑定 P 失败,那么只能走慢速路径,将当前任务放⼊待运⾏队列。

entersyscall -> reentersyscall -> entersyscall_sysmon -> notewakeup

entersyscallblock -> entersyscallblock_handoff -> handoffp(releasep)

exitsyscall -> exitsyscallfast -> exitsyscallfast_pidle

       -> exitsyscall0

 

 

目前的 Go 的调度器实现中设计了工作线程的自旋(spinning)状态

  1. 如果一个工作线程的本地队列、全局运行队列或网络轮询器中均没有可调度的任务,则该线程成为自旋线程;
  2. 满足该条件、被复始的线程也被称为自旋线程,对于这种线程,运行时不做任何事情。

自旋线程在进行暂止之前,会尝试从任务队列中寻找任务。当发现任务时,则会切换成非自旋状态, 开始执行

当一个

如果最后一个自旋线程发现工作并且停止自旋时,则复始一个新的自旋线程。 这个方法消除了不合理的线程复始峰值,且同时保证最终的最大

总的来说,调度器的方式可以概括为: 如果存在一个空闲的 这个方法消除了不合理的线程复始峰值,且同时保证最终的最大 CPU 并行度利用率。

 

 

因此,就绪一个

  • 提交一个
  • 执行
  • 检查

而从自旋到非自旋转换的一般流程为:

  • 减少
  • 执行
  • 在所有

 

 

 

M 的结构

  • 持有用于执行调度器的
  • 持有用于信号处理的
  • 持有线程本地存储
  • 持有当前正在运行的
  • 持有运行
  • 表示自身的自旋和非自旋状态
  • 管理在它身上执行的
  • 将自己与其他的
  • 持有当前线程上进行内存分配的本地缓存

 

调度器

  • 管理了能够将
  • 管理了空闲的
  • 管理了
  • 管理了可被复用的
  • 管理了

 

 

 

 

P,Processor,人为抽象的资源,数量通常等于cpu核数

P 只是处理器的抽象,而非处理器本身,它存在的意义在于实现工作窃取(work stealing)算法。 简单来说,每个 P 持有一个 G 的本地队列。

在没有

当引入了

 

golang grpc MaxConcurrentStreams 默认值是多少 golang sysmon_系统调用

golang grpc MaxConcurrentStreams 默认值是多少 golang sysmon_工作线程_02

 

保存 g 的运行入口 gostartcallfn 将要执行的函数

 

 

默认最多能创建10000个m,可用runtime/debug.SetMaxThreads修改这个值

 

 

⽤户可调⽤

 

 

 

所有

所有

 

m0 和 g0

每个m都有一个g0,运行在系统栈上,也叫线程栈或调度栈,g0不是go语句生成的,而是在创建m的时候由runtime生成的,一般用于执行调度、gc、内存管理等,g0不会阻塞,也不存在于任何列表中,栈不会被扫描。

m还有一个gsignal,用于处理信号,系统栈和信号栈不会自动增长

g0 和 gsignal 称为系统g,go语句创建的g称为用户g。

m0 和 m0 的 g0 是静态分配的,它们也叫做runtime.m0 和 runtime.g0,m0 是第一个系统线程,g0在此线程里执行引导程序, m0 与 g0 通过指针互相关联。