Go 并发实战:goroutine 与 channel 最佳实践

一、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 做超时与取消,才是生产级写法。