Go 语言协程管理精解

1.基础

协程切换需要操作寄存器,这些操作需要通过汇编辅助实现。另外,每一个协程都有一个协程栈,实际上协程栈也是有结构的。汇编程序和栈结构这些概念可能大部分开发者都不太了解,在介绍协程管理之间,先简要介绍。

1.1 汇编入门

学习 Go 语言协程还需要掌握汇编程序吗?其实不需要对汇编多么熟悉,只需要简单了解常用的一些汇编指令即可。

Go 语言本身就提供了很多工具,例如,编译工具 compile 用于编译 Go 程序,我们可以使用它将上述 Go 程序编译为汇编代码。编译命令以及编译后的汇编代码如下:

Go 复制代码
//-N 禁止优化 -l 禁止内联 -S 输出汇编
go tool compile -S -N -l test.go
// addSub 函数编译后的汇编代码
"".addSub STEXT nosplit size=49 args=0x20 locals=0x0
    0x0000 00000 (test.go:3)    MOVQ    $0, "".~r2+24(SP)
    0x0009 00009 (test.go:3)    MOVQ    $0, "".~r3+32(SP)
    0x0012 00018 (test.go:4)    MOVQ    "".a+8(SP), AX
    0x0017 00023 (test.go:4)    ADDQ    "".b+16(SP), AX
    0x001c 00028 (test.go:4)    MOVQ    AX, "".~r2+24(SP)
    0x0021 00033 (test.go:4)    MOVQ    "".a+8(SP), AX
    0x0026 00038 (test.go:4)    SUBQ    "".b+16(SP), AX
    0x002b 00043 (test.go:4)    MOVQ    AX, "".~r3+32(SP)
    0x0030 00048 (test.go:4)    RET
    
// main 函数编译后的汇编代码
"".main STEXT size=68 args=0x0 locals=0x28
    0x000f 00015 (test.go:7)      SUBQ    $40, SP
    0x0013 00019 (test.go:7)      MOVQ    BP, 32(SP)
    0x0018 00024 (test.go:7)      LEAQ    32(SP), BP
    0x001d 00029 (test.go:8)      MOVQ    $333, (SP)
    0x0025 00037 (test.go:8)      MOVQ    $222, 8(SP)
    0x002e 00046 (test.go:8)      CALL    "".addSub(SB)
    0x0033 00051 (test.go:9)      MOVQ    32(SP), BP
    0x0038 00056 (test.go:9)      ADDQ    $40, SP
    0x003c 00060 (test.go:9)      RET

如下所示:

协程退出

协程的入口函数为 gofunc,执行完成时,最后一条语句是 "RET" 汇编指令,它将从协程栈弹出 8 字节数据,并存储到程序计数器 PC,随后通过 "JMP" 指令跳转。"RET" 弹出的是函数 runtime.goexit 首地址,就相当于跳转到了函数 runtime.goexit,该函数代码如下:

Go 复制代码
//函数 runtime.goexit 是汇编代码实现的,调用了函数 runtime.goexit1
void goexit1(void){
	mcall(goexit0)
}

//系统栈执行该函数
func goexit0(gp *g){
	//设置协程状态,执行回收操作
	casgstatus(gp,_Grunning,_Gdead)
	//省略了清理协程相关数据的逻辑
	//添加到空闲队列
	gfput(_p_,gp)
	//调度
	schedule()
}

需要注意的是,函数 runtime.goexit 是汇编代码实现的,底层直接调用了函数 runtime.goexit1。同样,这里是通过函数 runtime.mcall 切换到系统栈,所以函数 runtime.goexit0 是在系统栈执行的,也是它完成的协程的收尾工作,包括修改协程状态为_Gdead,清理协程相关数据,将协程回收到逻辑处理器 P 的空闲队列,执行调度程序等。

相关推荐
djarmy4 小时前
MAIN.c(1): warning C318: can’t open file ‘STC8G.H’ 报错 解决 分析
c语言·开发语言·mongodb
HEJOO95 小时前
深入理解 Java volatile 关键字:原理、用法与常见误区
java·开发语言·spring
曹牧5 小时前
Java:no content to map due to end of input
java·开发语言
梦梦代码精5 小时前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
隔窗听雨眠5 小时前
记一次SQL Server数据库性能分析:从CPU100%到单配置修复的完整诊断
开发语言·数据库·php
David猪大卫5 小时前
【C++修炼】智能指针使用及原理
开发语言·c++·经验分享·笔记·学习·考研·面试
charlie1145141915 小时前
现代Qt开发之图像处理进阶:像素操作与格式转换
开发语言·图像处理·qt
李永奉5 小时前
中科蓝讯SDK开发-BT893x 面条耳机连接vivo手机后连接APP端,最后手机端设置页面手动断开蓝牙连接,此时耳机端假断开
c语言·开发语言·嵌入式硬件·物联网·智能手机·电脑
秦老师Q6 小时前
php零基础入门到实战,从语法到框架,一篇搞定
开发语言·php
驭渊的小故事7 小时前
多线程02
java·开发语言·jvm