Go 并发入门:goroutine 与 channel
Go 语言最大的卖点之一就是写并发代码很轻松。这篇文章用几个能直接运行的小例子,说明 goroutine 和 channel 的基本用法。
启动一个 goroutine
在函数调用前面加上 go 关键字,这个函数就会在新的 goroutine 里运行,当前代码不会停下来等它。
package main
import (
"fmt"
"time"
)
func sayHello(name string) {
fmt.Println("你好,", name)
}
func main() {
go sayHello("微风太阳")
// 主函数一结束整个程序就退出了,这里先简单等一下
time.Sleep(100 * time.Millisecond)
}
用
time.Sleep等待只是为了演示,真实项目里应该用sync.WaitGroup或 channel 来等待。
用 channel 传递数据
channel 可以理解成两个 goroutine 之间的一根管道:一边往里放,另一边从里面取。
无缓冲 channel
无缓冲 channel 要求发送方和接收方“同时到场”,任何一方先到都会停下来等另一方。
resultChannel := make(chan int)
go func() {
resultChannel <- 42
}()
result := <-resultChannel
fmt.Println(result) // 42
有缓冲 channel
有缓冲 channel 里面可以先存几个值,存满之前发送方不用等。
taskChannel := make(chan string, 3)
taskChannel <- "任务一"
taskChannel <- "任务二"
fmt.Println(len(taskChannel)) // 2
常见的坑
| 现象 | 原因 |
|---|---|
程序报错 all goroutines are asleep - deadlock! |
往无缓冲 channel 发数据,但没有人接收 |
| 程序直接退出,goroutine 里的内容没打印 | main 函数先结束了 |
| 关闭 channel 时 panic | 对同一个 channel 关闭了两次 |
小结
go 函数()启动并发任务。- channel 负责在 goroutine 之间传数据。
- 等待多个任务结束,用
sync.WaitGroup。