繁体   English   中英

Goroutines切换时,CPU上下文会发生什么?

[英]What happens with CPU context when Goroutines are switching?

如果我正确理解goroutine在系统线程之上的工作方式-它们从队列中一个接一个地运行。 但这是否意味着每个goroutine都会将其上下文加载/卸载到CPU? 如果是,系统线程和goroutines之间有什么区别?

最重要的问题是上下文切换的时间成本。 这是正确的吗?

检测哪种goroutine请求哪些数据的基础是什么? 例如:我正在从goroutine A向DB发送请求,并且不等待响应,并且同时切换到下一个goroutine。 系统如何理解请求来自A而不是来自B或C?

Goroutine,内存和OS线程

Go具有可根据需要增长的分段堆栈。 运行时执行调度,而不是操作系统。 运行时将goroutine复用到相对较少的实际OS线程上。

Goroutines切换成本

Goroutine是协同调度的,当发生切换时,仅需要保存/恢复3个寄存器-程序计数器,堆栈指针和DX。 从操作系统的角度来看,Go程序的行为就像一个事件驱动程序。

Goroutine和CPU

您不能直接控制运行时将创建的线程数。 通过调用runtime.GOMAXPROCS(n)设置变量GOMAXPROCS,可以设置程序使用的处理器内核数量。

程序计数器

和一个完全不同的故事

在计算中,程序是计算机要执行的一组特定的有序操作。 指令是程序赋予计算机处理器的命令。 在计算机内,地址是内存或存储中的特定位置。 程序计数器寄存器是处理器使用的一小部分数据保存位置之一。

这是关于程序如何工作以及如何相互通信的另一个故事,它与goroutine主题没有直接关系。

资料来源:

Gs,Ms,Ps

“ G”只是一个goroutine。 用类型g表示。 当goroutine退出时,其g对象将返回到空闲gs池中,以后可用于其他一些goroutine。

“ M”是一个OS线程,可以执行用户Go代码,运行时代码,系统调用或处于空闲状态。 用类型m表示。 一次可以有任意多个M,因为在系统调用中可能会阻塞任何数量的线程。

最后,“ P”表示执行用户Go代码所需的资源,例如调度程序和内存分配器状态。 用类型p表示。 确实有GOMAXPROCSP。 可以将AP视为OS调度程序中的CPU,并将p类型的内容视为每个CPU状态。 这是放置状态的好地方,该状态需要进行分片以提高效率,但不必按线程或按规范进行分配。

调度程序的工作是匹配一个G(要执行的代码),一个M(要在哪里执行)和一个P(执行它的权利和资源)。 当M停止执行用户Go代码时(例如通过输入系统调用),它将M返回到空闲的P池。 为了恢复执行用户Go代码(例如,从系统调用返回时),它必须从空闲池中获取P。

所有g,m和p对象都是堆分配的,但是从不释放,因此它们的内存保持类型稳定。 结果,运行时可以避免调度程序深度的写障碍。

用户堆栈和系统堆栈

每个非死G都有一个与之关联的用户堆栈,这是用户Go代码执行的对象。 用户堆栈开始时很小(例如2K),并且会动态增长或缩小。

每个M都有一个与之关联的系统堆栈(也称为M的“ g0”堆栈,因为它是作为存根G实现的),在Unix平台上,还有一个信号堆栈(也称为M的“ gsignal”堆栈)。 系统和信号堆栈无法增长,但足够大以执行运行时和cgo代码(纯Go二进制文件中为8K; cgo二进制文件中系统分配)。

运行时代码通常使用systemstack,mcall或asmcgocall临时切换到系统堆栈,以执行不能被抢占,不能增长用户堆栈或切换用户goroutine的任务。 在系统堆栈上运行的代码是隐式不可抢占的,并且垃圾收集器不会扫描系统堆栈。 在系统堆栈上运行时,当前用户堆栈不用于执行。

参考: https : //github.com/golang/go/blob/master/src/runtime/HACKING.md

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM