一、goroutine:轻量到可以”随便开”
Go 的并发单元叫 goroutine,初始栈仅几 KB,由 runtime 调度,开上万个也很便宜。但它不是 OS 线程,别滥用——开太多且阻塞在系统调用上仍会拖垮调度。
二、channel:用通信替代共享内存
Go 的哲学:”不要通过共享内存来通信,要通过通信来共享内存”。channel 是 goroutine 间传递数据的管道。
func worker(jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * j
}
}
func main() {
jobs := make(chan int, 10)
results := make(chan int, 10)
for w := 0; w < 3; w++ {
go worker(jobs, results)
}
for i := 1; i <= 5; i++ {
jobs <- i
}
close(jobs)
for i := 0; i < 5; i++ {
<-results
}
}
三、WaitGroup 等待一批任务
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
doWork(id)
}(i)
}
wg.Wait() // 等全部完成
四、常见坑
| 坑 | 解法 |
|---|---|
| goroutine 泄漏 | 用 context 取消、channel 要有收尾,别让 goroutine 永久阻塞 |
| 共享变量竞态 | 用 mutex 或靠 channel 串行化访问 |
| 循环变量捕获 | go func(id int){…}(i) 传参,别闭包捕获循环变量 |
五、什么时候用并发
IO 密集(网络、磁盘)并发收益最大;CPU 密集注意 GOMAXPROCS 与避免锁竞争。配合 context.Context 做超时与取消,才是生产级写法。