[英]What happens with CPU context when Goroutines are switching?
如果我正确理解goroutine在系统线程之上的工作方式-它们从队列中一个接一个地运行。 但这是否意味着每个goroutine都会将其上下文加载/卸载到CPU? 如果是,系统线程和goroutines之间有什么区别?
最重要的问题是上下文切换的时间成本。 这是正确的吗?
检测哪种goroutine请求哪些数据的基础是什么? 例如:我正在从goroutine A向DB发送请求,并且不等待响应,并且同时切换到下一个goroutine。 系统如何理解请求来自A而不是来自B或C?
Go具有可根据需要增长的分段堆栈。 运行时执行调度,而不是操作系统。 运行时将goroutine复用到相对较少的实际OS线程上。
Goroutine是协同调度的,当发生切换时,仅需要保存/恢复3个寄存器-程序计数器,堆栈指针和DX。 从操作系统的角度来看,Go程序的行为就像一个事件驱动程序。
您不能直接控制运行时将创建的线程数。 通过调用runtime.GOMAXPROCS(n)
设置变量GOMAXPROCS,可以设置程序使用的处理器内核数量。
和一个完全不同的故事
在计算中,程序是计算机要执行的一组特定的有序操作。 指令是程序赋予计算机处理器的命令。 在计算机内,地址是内存或存储中的特定位置。 程序计数器寄存器是处理器使用的一小部分数据保存位置之一。
这是关于程序如何工作以及如何相互通信的另一个故事,它与goroutine主题没有直接关系。
资料来源:
“ 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的任务。 在系统堆栈上运行的代码是隐式不可抢占的,并且垃圾收集器不会扫描系统堆栈。 在系统堆栈上运行时,当前用户堆栈不用于执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.