Go 协程 (goroutine) 是指在后台中运行的轻量级执行线程,go 协程是 Go 中实现并发的关键组成部分。

在上次的课程中,我们学习了 Go 的并发模型。由于 Go 协程相对于传统操作系统中的线程 (thread) 是非常轻量级的,因此对于一个典型的 Go 应用来说,有数以千计的 Go 协程并发运行的情形是十分常见的。并发可以显著地提升应用的运行速度,并且可以帮助我们编写关注点分离(Separation of concerns,Soc)的代码。

什么是 Go 协程?

我们也许在理论上已经知晓 Go 协程是如何工作的,但是在代码层级上,go 协程何许物也?其实,go 协程看起来只是一个与其他众 Go 协程并发运行的一个简单函数或者方法,但是我们并不能想当然地从函数或者方法中的定义来确定一个 Go 协程,go 协程的确定还是要取决于我们如何去调用。

gogo

举个简单的栗子:

Hello WorldprintHellomainprintHello

下面,让我们尝试从同一个函数创建 Go 协程:

go
Hello World
go printHello()printHello
maingo 主协程(main Goroutine,下面简称主协程)主协程printHelloprintHello 协程mainprintHello主协程主协程printHello 协程主协程printHello 协程
time.Sleep()
time.Sleep(10 * time.Millisecond)主协程printhello 协程time.Sleep(10 * time.Millisecond)主协程
printHello 协程printHello 协程主协程
printHellotime.Sleep(time.Millisecond)non-sleeping主协程主协程

上面的程序依旧和之前的例子一样,输出以下相同的结果:

要是,我把这个printHello 协程中的休眠 1 毫秒改成休眠 15 毫秒,这个结果又是如何呢?

在这个例子中,与其他的例子最大的区别就是printHello 协程比主协程的休眠时间还要长,很明显,主协程要比 printHello 协程唤醒要早,这样的结果就是主协程即使唤醒后执行完所有的语句,printHello 协程还是在休眠状态。之前提到过,主协程比较特殊,如果主协程执行结束后整个程序就要退出,所以 printHello 协程得不到机会去执行下面的输出的语句了,所以以上的程序的数据结果如下:

使用多 Go 协程

就像之前我所提到过的,你可以随心所欲地创建多个 Go 协程。下面让我们定义两个简单的函数,一个是用于顺序打印某个字符串中的每个字符,另一个是顺序打印出某个整数切片中的每个数字。

在上图中的程序中,我们连续地创建了两个 Go 协程,程序输出的结果如下:

time.Sleep
getCharsgetDigitsgetDigitsgetCharsgetCharsgetChars

我们在 Windows 上运行上面的程序,得到了以下的结果:

通过以上输出结果可以证明我们之前对输出的讨论。对于这个结果,我们可以通过下面的的程序运行图来解释。需要注意的是,我们在图中定义一个输出语句大约会花费 1ms 的 CPU 时间,而这个时间相对于 200ms 来说是可以忽略不计的。

time.Sleeptime.Sleep

匿名 Go 协程

即时调用函数(Immedietly invoked function)printHello

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

需要注意的是,所有的 Go 协程都是匿名的,因为我们从 一课中学到,go 协程是不存在标识符的,在这里所谓的匿名 Go 协程只是通过匿名函数来创建的 Go 协程罢了


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