Golang Go语言中刚接触,了解到切换协程仅需保存3个寄存器,那么剩余的怎么办呢,比如ecx,eax等

发布于 1周前 作者 htzhanglong 来自 Go语言

go 只保存了,pc ,sp 和 dx


Golang Go语言中刚接触,了解到切换协程仅需保存3个寄存器,那么剩余的怎么办呢,比如ecx,eax等
9 回复

是因为 go 与 java 一样都是基于栈的虚拟机?

更多关于Golang Go语言中刚接触,了解到切换协程仅需保存3个寄存器,那么剩余的怎么办呢,比如ecx,eax等的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


应该是和 go 的调用约定有关,只保存被调用者保存( callee-saved )的寄存器,调用者保存( caller-saved )的寄存器是由函数本身生成的代码自己负责的。

因为协程不是像线程那样由 OS 强行抢占的,是只有在特定的切换点才能切换,可以把这个切换的过程理解成一个特殊的函数调用 [而且 go 里面就有这么一个函数 runtime.Gosched()] 。caller-saved 寄存器如果需要保存的话,编译器会生成相应的代码,不用协程调度器保存。

这个跟 go 无关把。你协程本来也应该在函数内,其他寄存器在进入函数前都 pushall 了,只要协程能找回栈信息就能恢复把。

我有个印象,可能记错别太当真,就是,golang 会把函数内所有变量和参数都复制到栈上,所以可能只要 sp 指回来整个栈帧就能恢复

分版本,go1.15 之前用栈传参,go1.16 之后用寄存器传参了

我认为:剩余的寄存器,比如 ecx ,eax 等,协程切换时,保存在 go 的栈上。(不管是老的,还是新的调用规约)

eax ebx ecx edx 这些数据寄存器本来就不会跨函数吧,所以这几个是不需要保存的,不然每次函数调用也需要保存,代价太高。

Goroutine 中的寄存器并不是实际物理寄存器,Go 使用的寄存器是从 Plan 9 继承来的寄存器规范,跟物理寄存器并非 1:1 严格映射的。

在Go语言的并发模型中,协程(goroutine)的轻量级实现确实得益于其高效的上下文切换机制。你提到的切换协程仅需保存3个寄存器,这通常指的是Go运行时为了管理协程切换而特别关注的几个关键寄存器(比如程序计数器PC、栈指针SP和栈基指针BP等),这些寄存器对于恢复和继续执行协程至关重要。

至于你提到的ecx、eax等寄存器,它们属于x86架构的通用寄存器,在Go协程的上下文切换中并非不处理,而是处理方式有所不同:

  1. 通用寄存器状态:在协程切换时,Go的运行时系统不会显式地保存和恢复所有通用寄存器的状态,因为这些寄存器的值通常随着函数的调用和返回而变化,且大多数情况下,这些变化是局部的,不影响协程的整体执行状态。

  2. 调用约定:Go编译器和运行时遵循特定的调用约定,确保在函数调用和返回时,必要的寄存器值能够通过栈或其他方式正确传递和恢复。

  3. 上下文局部性:对于需要跨协程保存和恢复的数据,Go程序员通常会使用显式的内存变量或通过通道(channel)等同步机制来传递,而不是依赖寄存器的隐式状态。

因此,虽然ecx、eax等通用寄存器在协程执行中扮演着重要角色,但在协程切换时,Go的运行时系统通过合理的调用约定和内存管理策略,确保了这些寄存器的值在需要时能够被正确处理和恢复。

回到顶部