goroutine 是一个在后台运行的轻量级执行线程。goroutines 是在 Go 中实现并发的关键。

在前一课(Golang 并发之一 ( go并发模型))中,我们学习了 Go 的并发模型。由于与操作系统线程相比,goroutines 是轻量级的,因此 Go 应用程序同时运行数千个 goroutines 是很常见的。并发可以显着加速应用程序,并帮助我们编写关注点分离 (SoC) 的代码。

什么是goroutine?

我们理解了 goroutine 理论上是如何工作的,但是在代码中,它是什么?其实,goroutine 只是一个与其他 goroutine 在后台同时运行的函数或方法。决定它是否为 goroutine 的不是函数或方法定义,而是由我们如何调用它决定的。

gogo
正常函数调用
printHelloHello World!mainprintHello()

现在让我们从同一个 printHello 函数创建 goroutine。

go并发函数调用

那么,根据 goroutine 语法,我们在函数调用前加上 go 关键字,程序执行得很好。它产生了以下结果:

main execution started
main execution stopped

奇怪的是,"Hello World"没有被打印出来。所以发生了什么事?

goroutines 总是在后台运行。当一个 goroutine 被执行时, 调度器不会阻塞程序的执行,不像我们在前面的例子中看到的普通函数调用。相反,控制会立即执行到下一行代码,并且忽略 goroutine 的任何返回值。但即便如此,为什么我们看不到函数输出呢?

main goroutinegoprintHello goroutine
main goroutineprintHello goroutinemain goroutinemain goroutineprintHello goroutinetime.Sleep()
阻塞main,调度printHello
main goroutinetime.Sleep(10 * time.Millisecond)printHello goroutinemain goroutineprintHello goroutinemain goroutine
main execution started
Hello World!
main execution stopped
main goroutine
main goroutineprintHello goroutineprintHello goroutineprintHello goroutinemain goroutine
休眠goroutine

上面的程序仍然会打印相同的结果

main execution started
Hello World!
main execution stopped
printHello goroutine
main goroutine 10ms后退出,printHello并不能被打印
main goroutineprintHello goroutineprintHello goroutine
main execution started
main execution stopped

使用多个goroutines

正如我之前所说,您可以创建尽可能多的 goroutine。让我们定义两个简单的函数,一个打印字符串的字符,另一个打印整数切片的数字。

多路goroutine

在上面的程序中,从两个函数调用中依次创建了2个goroutine,然后调度两个goroutine 中的任何一个,调度哪个 goroutine 由调度程序决定。这将产生以下结果

main execution started
H e l l o 1 2 3 4 5 
main execution stopped

我们在上述程序中加入时间线,以更明白的显示调度过程

timelime print
main goroutine
main execution started at time 869ns
1 at time 85.786µs                  |
h at time 74.176µs                  | 几乎在统一时间执行
e at time 12.69351ms                                |
l at time 24.539522ms                               | <- 10ms 的间隔
2 at time 30.357187ms
l at time 36.15972ms
o at time 46.376659ms
3 at time 61.458487ms                                                                       |
4 at time 95.741154ms                                                                       |    
5 at time 128.897282ms                                                                      | <- 30ms的间隔

 main execution stopped at time 201.411518ms                             | 200 ms 后执行

通过下面的执行图,我们可以看到我们谈论的模式, 一切都会变的清晰。估计打印命令需要 1 毫秒的 CPU 时间,与 200 毫秒的规模相比,这是可以忽略不计的。

执行图
channel

匿名 goroutine

如果匿名函数可以存在,那么匿名 goroutine 也可以存在。让我们修改我们之前的 printHello goroutine 示例。

匿名goroutine

结果非常明显,因为我们在同一语句中定义了函数并作为 goroutine 执行。

正如我们从并发课程中学到的那样,所有 goroutine 都是匿名的,因为 goroutine 没有身份。但我们称其为创建它的函数是匿名的。

参考文章