欢迎来到 Golang 系列教程[1]的第 21 篇。

在前面的教程里,我们探讨了并发,以及并发与并行的区别。本教程则会介绍在 Go 语言里,如何使用 Go 协程(Goroutine)来实现并发。

Go 协程是什么?

Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是轻量级线程。与线程相比,创建一个 Go 协程的成本很小。因此在 Go 应用中,常常会看到有数以千计的 Go 协程并发地运行。

Go 协程相比于线程的优势

  • 相比线程而言,Go 协程的成本极低。堆栈大小只有若干 kb,并且可以根据应用的需求进行增减。而线程必须指定堆栈的大小,其堆栈是固定不变的。
  • Go 协程会复用(Multiplex)数量更少的 OS 线程。即使程序有数以千计的 Go 协程,也可能只有一个线程。如果该线程中的某一 Go 协程发生了阻塞(比如说等待用户输入),那么系统会再创建一个 OS 线程,并把其余 Go 协程都移动到这个新的 OS 线程。所有这一切都在运行时进行,作为程序员,我们没有直接面临这些复杂的细节,而是有一个简洁的 API 来处理并发。
  • Go 协程使用信道(Channel)来进行通信。信道用于防止多个协程访问共享内存时发生竞态条件(Race Condition)。信道可以看作是 Go 协程之间通信的管道。我们会在下一教程详细讨论信道。

如何启动一个 Go 协程?

go

让我们创建一个 Go 协程吧。

package main

import (
 "fmt"
)

func hello() {
 fmt.Println("Hello world goroutine")
}
func main() {
 go hello()
 fmt.Println("main function")
}

在线运行程序[2]

go hello()hello()main()

运行一下程序,你会很惊讶!

main function
  • 启动一个新的协程时,协程的调用会立即返回。与函数不同,程序控制不会去等待 Go 协程执行完毕。在调用 Go 协程之后,程序控制会立即返回到代码的下一行,忽略该协程的任何返回值。
  • 如果希望运行其他 Go 协程,Go 主协程必须继续运行着。如果 Go 主协程终止,则程序终止,于是其他 Go 协程也不会继续运行。
go hello()hellomain functionhello

我们现在修复这个问题。

package main

import (
 "fmt"
 "time"
)

func hello() {
 fmt.Println("Hello world goroutine")
}
func main() {
 go hello()
 time.Sleep(1 * time.Second)
 fmt.Println("main function")
}

在线运行程序[3]

go hello()Hello world goroutinemain function

在 Go 主协程中使用休眠,以便等待其他协程执行完毕,这种方法只是用于理解 Go 协程如何工作的技巧。信道可用于在其他协程结束执行之前,阻塞 Go 主协程。我们会在下一教程中讨论信道。

启动多个 Go 协程

为了更好地理解 Go 协程,我们再编写一个程序,启动多个 Go 协程。

package main

import (
 "fmt"
 "time"
)

func numbers() {
 for i := 1; i <= 5; i++ {
  time.Sleep(250 * time.Millisecond)
  fmt.Printf("%d ", i)
 }
}
func alphabets() {
 for i := 'a'; i <= 'e'; i++ {
  time.Sleep(400 * time.Millisecond)
  fmt.Printf("%c ", i)
 }
}
func main() {
 go numbers()
 go alphabets()
 time.Sleep(3000 * time.Millisecond)
 fmt.Println("main terminated")
}

在线运行程序[5]

numbers125alphabeteaenumbersalphabete

该程序会输出:

1 a 2 3 b 4 c 5 d e main terminated

程序的运作如下图所示。为了更好地观看图片,请在新标签页中打开。

numbersalphabets0 ms250 ms123250 ms1500 ms21 a 2 3 b 4 c 5 d e main terminated

Go 协程的介绍到此结束。祝你愉快。

上一教程 - 并发入门

下一教程 - 信道[6]

via: https://golangbot.com/goroutines/

作者:Nick Coghlan[7]译者:Noluye[8]校对:polaris1119[9]

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

参考资料

Sleep