ℹ️本文基于 Go 1.14。

在 Go 中,协程就是一个包含程序运行时的信息的结构体,如栈,程序计数器,或者它当前的 OS 线程。调度器还必须注意 Goroutine 的开始和退出,这两个阶段需要谨慎管理。

开启

开启一个协程的处理过程相当简单。我们用一个程序作为例子:

main
  • 创建栈
  • 收集当前程序计数器或调用方数据的信息
  • 更新协程内部数据,如 ID 或 状态

然而,协程没有立即获取运行时状态。新创建的协程被加入到了本地队列的最前端,会在 Go 调度的下一周期运行。下面是现在这种状态的示意图:

把协程放在队列的前端,这样它就会在当前协程运行之后第一个运行。如果有工作窃取发生,它不是在当前线程就是在另一个线程运行。

我推荐你阅读我的文章 来获取更多信息。

在汇编指令中也可以看到协程的创建过程:

协程被创建并被加入到本地协程队列后,它直接执行主函数的下一个指令。

退出

协程结束时,为了不浪费 CPU 资源,Go 必须调度另一个协程。这也使协程可以在以后复用。

在我的文章 中你可以找到更多信息。

goexitgoexit

根据输出信息进行堆栈追踪:

asm_amd64
g0
runtime.Goexit()

这个函数首先运行 defer 中的函数,然后会运行前面在协程退出时我们看到的那个函数。


本文由 原创编译, 荣誉推出