← Backend / Go / 基础专题

22_goroutine与同步

启动并发任务,理解主函数退出、等待和共享状态竞争。

Go 基础专题 22:goroutine 与同步

学习目标:启动并发任务,理解主函数退出、等待和共享状态竞争。

核心知识

在函数调用前加 go 会启动 goroutine,调用者不等待它完成。主函数一旦返回,进程结束,未完成的 goroutine 不会自动留下来。因此并发任务需要明确等待机制。sync.WaitGroup 可等待多个任务完成;每个任务结束要调用 Done()。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Done()
            fmt.Println(n)
        }(i)
    }
    wg.Wait()
}

输出顺序不保证为 0、1、2。多个 goroutine 同时读写同一变量可能产生数据竞争;用 channel 传值、sync.Mutex 保护共享数据,或设计单一所有者。go test -race ./... 可在支持的平台检测运行到的竞争路径,但不能代替设计和测试。

并发不一定让程序更快:任务太小、共享锁太多或 I/O 不可并行时,调度开销可能超过收益。先保证正确,再测量性能。

逐步理解

先运行示例多次,观察打印顺序变化,再解释为何 Wait 只保证完成、不保证顺序。若每个任务都执行 counter++,即使最终数字偶尔正确,也不说明没有竞争。把共享状态交给单个 goroutine,或用锁保护整个读改写过程。等待和取消是两个不同需求:WaitGroup 不会主动停止卡住的任务。

动手练习

练习:启动两个任务分别打印 A、B,确保主函数等它们完成。答案要点:Add(2),每个任务 defer Done(),最后 Wait()。