Go 语言并发编程入门
Goroutine
Goroutine 是 Go 并发编程的核心。它是一种轻量级线程,由 Go 运行时管理而非操作系统。创建 goroutine 的成本极低,初始栈大小仅几 KB,可根据需要动态增长。
go func() {
fmt.Println("Hello from goroutine")
}()
Channel
Channel 是 goroutine 之间的通信管道,遵循 "Do not communicate by sharing memory; instead, share memory by communicating" 的设计哲学。
无缓冲 channel
无缓冲 channel 同步阻塞,发送和接收必须同时准备好:
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
有缓冲 channel
有缓冲 channel 在缓冲区未满时不会阻塞:
ch := make(chan string, 3)
ch <- "a"
ch <- "b"
ch <- "c" // 缓冲区满之前不会阻塞
select 多路复用
select 语句允许 goroutine 同时等待多个 channel 操作:
select {
case msg := <-ch1:
fmt.Println(msg)
case msg := <-ch2:
fmt.Println(msg)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
}
WaitGroup
sync.WaitGroup 用于等待一组 goroutine 完成:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
doWork(id)
}(i)
}
wg.Wait()
Mutex
当多个 goroutine 需要访问共享资源时,使用 sync.Mutex 保护临界区:
var mu sync.Mutex
var counter int
for i := 0; i < 1000; i++ {
go func() {
mu.Lock()
counter++
mu.Unlock()
}()
}
常见模式
生产者-消费者
func producer(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int) {
for v := range ch {
fmt.Println(v)
}
}
Pipeline 模式
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
注意事项
- 避免 goroutine 泄漏:确保 goroutine 能正常退出
- 使用
context包管理取消信号和超时 - 不要猜测 goroutine 的执行顺序,使用 channel 或 WaitGroup 同步
- 对关闭的 channel 发送数据会 panic