goroutine
什么是 goroutine
goroutine 是 Go 运行时管理的轻量级执行单元,类似线程但成本极低:初始栈仅 2KB(线程通常为 MB 级),创建与切换均由运行时调度器完成,单个进程可轻松承载百万级 goroutine。
创建 goroutine
在函数调用前添加 go 关键字即可并发执行:
go 语句立即返回,不等待函数结束。若 main 先退出,所有子 goroutine 会被强制终止——这也是上例需要 Sleep 的原因。生产代码不使用 Sleep 同步,而是使用 WaitGroup 或 channel。
sync.WaitGroup:等待一组 goroutine
Tip
WaitGroup 必须以指针传递(内部含计数器状态)。wg.Add(1) 应在启动 goroutine 之前调用,wg.Done() 用 defer 保证执行。
Go 1.25 引入 wg.Go(func(){...}) 方法,将 Add/Done 封装为一行调用。
匿名 goroutine 与参数捕获
Warning
Go 1.22 起,for range 循环变量每次迭代均为新变量,闭包直接捕获是安全的;Go 1.21 及更早版本中,所有迭代共享同一变量,必须像上例那样通过函数参数显式传入,否则存在数据竞争。
goroutine 不是免费的
尽管创建成本极低,仍需管理其生命周期。无法退出、永久阻塞的 goroutine 会造成泄漏,典型诱因包括:
- 向无人接收的 channel 发送数据。
- 从已关闭且无数据的 channel 接收数据。
- 忘记取消带循环的 goroutine(应配合 context 处理)。
并发模式:批量并行处理
Tip
上例中每个 goroutine 只写自己对应的下标,属于并发安全写法。若多个 goroutine 写同一元素或同一 map,则需要 channel 或 sync.Mutex。
小结
go关键字启动轻量协程,调用方需自行管理等待与退出。sync.WaitGroup是等待一批任务的标准工具。- 循环变量捕获注意 Go 版本差异;goroutine 泄漏需用 context 与 channel 设计规避。