go程序启动即有main goroutine,其他需显式go启动;main退出则程序终止,其余goroutine被强制回收;常见问题为go sayhello()后无输出,因main快速退出;调试可用time.sleep,生产环境应使用sync.waitgroup配合add、done、wait确保等待。

Go 程序一启动就有 main goroutine,其他 goroutine 必须显式用 go 启动;不加同步机制时,main 函数退出即整个程序终止,其余 goroutine 会被强制回收——这不是 bug,是设计使然。
goroutine 启动后 main 就退出了,输出没打印出来
这是最常遇到的现象:写了 go sayHello(),但控制台什么都没输出。根本原因是主 goroutine 执行完 main 函数就直接退出,调度器不会等其他 goroutine。
- 临时调试可用
time.Sleep,比如time.Sleep(100 * time.Millisecond),但仅限 demo,不能用于生产 - 真正可靠的等待方式是
sync.WaitGroup:在启动前调用wg.Add(1),goroutine 结束前调用wg.Done(),主 goroutine 调用wg.Wait() - 注意
wg必须传指针,否则Done()修改的是副本,Wait()永远阻塞
for 循环里启动 goroutine,结果全打印同一个数字
典型错误写法:for i := 0; i 。所有 goroutine 共享同一个变量 <code>i 的地址,循环结束时 i == 3,所以输出全是 3。
- 正确做法是把当前值作为参数传入匿名函数:
go func(val int) { fmt.Println(val) }(i) - 或者用局部变量捕获:
for i := 0; i (利用短变量声明创建新作用域) - 切记:闭包捕获的是变量引用,不是值;循环变量在每次迭代中复用内存地址
goroutine 数量失控导致内存暴涨
有人写 for range ch { go handle(msg) } 处理每条消息,但没做限流,上游消息一多,瞬间 spawn 几千个 goroutine,RSS 内存飙升。
- goroutine 初始栈仅 2KB,但会动态增长;百万级 goroutine 可能吃掉 GB 级内存
- 避免无限制创建:用 worker pool 模式,固定数量 goroutine 从 channel 消费任务,例如
for w := 0; w - 监控当前数量可用
runtime.NumGoroutine(),上线前建议加日志或 metrics 上报
goroutine 泄漏:channel 接收端没关,发送端一直阻塞
常见于未关闭的 channel 和无缓冲 channel 的误用。比如 ch := make(chan int),只在 goroutine 里 ch ,但主 goroutine 没 <code> 或已退出,该 goroutine 就永远卡在发送上。
- 无缓冲 channel 发送/接收必须配对;有缓冲 channel 超过容量也会阻塞
- 务必确保 sender 和 receiver 生命周期匹配,常用
close(ch)+range ch配合select处理超时 - 泄漏不易察觉,但会导致 goroutine 数持续上涨,
pprof的/debug/pprof/goroutine?debug=2是排查利器
goroutine 不是免费的,它的轻量是相对 OS 线程而言;真正麻烦的从来不是“怎么开”,而是“怎么收尾”和“怎么控量”。写完 go 关键字,得立刻想清楚:谁等它、谁关它、它会不会卡住、它资源用完还活着吗。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











