龙空技术网

Go之旅:Goroutine 的开启和退出

Go语言中文网 1203

前言:

如今朋友们对“下载phpstudy的步骤出现runtime”可能比较看重,看官们都需要分析一些“下载phpstudy的步骤出现runtime”的相关知识。那么小编在网上网罗了一些对于“下载phpstudy的步骤出现runtime””的相关文章,希望你们能喜欢,看官们快快来了解一下吧!

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

ℹ️本文基于 Go 1.14。

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

如果你想了解更多关于栈和程序计数器的信息,我推荐你阅读我的文章 Go:协程切换时涉及到哪些资源?[1]

开启

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

main 函数在打印信息之前开启了一个协程。由于协程会有自己的运行时间,因此 Go 通知运行时配置一个新协程,意味着:

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

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

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

我推荐你阅读我的文章 Go: Go 调度器中的工作窃取[2]来获取更多信息。

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

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

退出

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

在我的文章 Go: 协程怎么复用?[3]中你可以找到更多信息。

然而,Go 需要一个能识别到协程结束的方法。这个方法是在协程创建时控制的。创建协程时,Go 在将程序计数器设置为协程真实调用的函数之前,将堆栈设置为名为 goexit 的函数。这个技巧可以使协程在结束时必须调goexit 函数。下面的程序可以使我们理解得更形象:

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

/path/to/src/main.go:16/usr/local/go/src/runtime/asm_amd64.s:1373

用汇编写的 asm_amd64 文件包含这个函数:

之后,Go 切换到 g0 调度另一个协程。

我们也可以调用 runtime.Goexit() 来手动终止协程:

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

via:

作者:Vincent Blanchon[4]译者:lxbwolf[5]校对:polaris1119[6]

本文由 GCTT[7] 原创编译,Go 中文网[8] 荣誉推出

参考资料

[1]

Go:协程切换时涉及到哪些资源?:

[2]

Go: Go 调度器中的工作窃取:

[3]

Go: 协程怎么复用?:

[4]

Vincent Blanchon:

[5]

lxbwolf:

[6]

polaris1119:

[7]

GCTT:

[8]

Go 中文网:

标签: #下载phpstudy的步骤出现runtime