Go 并发编程:goroutine 与 channel
Go 语言以简洁的并发模型著称。本文梳理 goroutine 与 channel 的核心用法。
goroutine
启动一个 goroutine 非常简单:
1 2 3
| go func() { fmt.Println("hello from goroutine") }()
|
注意:
main 结束时不会等待 goroutine 完成
- goroutine 泄漏是常见 bug
channel
无缓冲 channel
1 2 3 4 5
| ch := make(chan int) go func() { ch <- 42 }() fmt.Println(<-ch)
|
有缓冲 channel
1 2 3 4
| ch := make(chan int, 3) ch <- 1 ch <- 2
|
常用并发模式
1. Worker Pool
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| jobs := make(chan int, 100) results := make(chan int, 100)
for w := 1; w <= 3; w++ { go worker(w, jobs, results) }
for j := 1; j <= 5; j++ { jobs <- j } close(jobs)
for a := 1; a <= 5; a++ { <-results }
|
2. select 多路复用
1 2 3 4 5 6
| select { case msg := <-ch1: fmt.Println(msg) case <-time.After(1 * time.Second): fmt.Println("timeout") }
|
3. context 取消
1 2 3 4 5 6 7 8 9 10
| ctx, cancel := context.WithCancel(context.Background()) go func() { select { case <-ctx.Done(): return case <-ch: } }() cancel()
|
常见陷阱
| 陷阱 |
解决 |
| goroutine 泄漏 |
用 context 控制生命周期 |
| 数据竞争 |
用 sync.Mutex 或 channel |
| 死锁 |
注意 channel 收发的对应 |
总结
Go 的并发模型哲学是”通过通信来共享内存,而不是通过共享内存来通信”。本站后续会持续更新 Go 并发实战内容。