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()。