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



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

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

哪些机制正在检测哪些Goroutine请求哪些数据?例如:我将请求从Goroutine A发送到DB,并且不等待响应,同时也发生了切换到下一个Goroutine。系统如何理解请求来自A,而不是来自B或C?

goroutines,内存和OS线程

go有一个分段的堆栈,可根据需要生长。进行运行时进行调度,而不是操作系统。运行时将goroutines多路复用到相对较少的真实操作系统上。

goroutines开关成本

goroutines是合作计划的,当开关发生时,只需保存/还原3个寄存器 - 程序计数器,堆栈指针和DX。从操作系统的角度来看,GO程序作为事件驱动的程序的行为。

goroutines和cpu

您无法直接控制运行时将创建的线程数。可以通过使用runtime.GOMAXPROCS(n)的呼叫设置可变的GomaxProcs来设置程序使用的处理器核心数。

程序计数器

和一个完全不同的故事

在计算中,程序是一组特定的有序操作,供计算机执行。指令是通过程序给计算机处理器的订单。在计算机中,地址是内存或存储中的特定位置。程序计数器注册是处理器使用的一小部分数据保存位置之一。

这是一个不同的故事,讲述程序如何相互工作和沟通,并且与Goroutine主题无直接相关。

来源:

  • http://blog.nindalf.com/how-goroutines-work/
  • https://gobyexample.com/goroutines
  • http://tleyden.github.io/blog/2014/10/10/30/goroutines-vs-threads/
  • http://whatis.techtarget.com/definition/program-counter

GS,MS,PS

a" g"只是一个goroutine。它由类型G表示。当Goroutine退出时,其G对象将返回到一个自由GS池,以后可以重复用于其他一些Goroutine。

" M"是一个操作系统,可以执行用户GO代码,运行时代码,系统调用或闲置。它由类型M表示。一次可以有任何数量的MS,因为在系统调用中可能会阻止任何数量的线程。

最后," p"代表执行用户GO代码所需的资源,例如调度程序和内存分配器状态。它由类型P。完全有GomaxProcs PS。可以将p视为OS调度程序中的CPU和P类型的内容(如PER-CPU状态)。这是一个要付出效率的状态的好地方,但不需要每读或人均。

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

所有的G,M和P对象都分配了堆,但永远不会被释放,因此它们的内存仍然稳定。结果,运行时可以避免在调度程序的深处写入障碍。

用户堆栈和系统堆栈

每个非死亡G都有与之关联的用户堆栈,这是用户GO代码执行的。用户堆栈从小(例如2K)开始,并动态增长或收缩。

每个M都有与之相关的系统堆栈(也称为M的" G0"堆栈,因为它被实现为存根G),并且在UNIX平台上,一个信号堆栈(也称为M的" Gsignal"堆栈)。系统和信号堆栈不能增长,但是足够大以执行运行时和CGO代码(纯GO二进制;在CGO二进制中分配的系统)。

运行时代码通常会使用SystemStack,MCALL或ASMCGOCALL暂时切换到系统堆栈,以执行不得抢占的任务,不得将用户堆栈增长或该切换用户Goroutines。在系统堆栈上运行的代码隐含不可撤销,并且垃圾收集器不会扫描系统堆栈。在系统堆栈上运行时,当前用户堆栈不用于执行。

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

最新更新