必须配节流,不能裸写go func();http handler等场景直接go启动协程会将请求速率映射为goroutine创建速率,缺乏超时、退出控制和并发限制将引发oom与调度崩溃。

goroutine 启动必须配节流,不能裸写 go func()
框架里最常犯的错,就是在 HTTP handler、消息消费循环或定时任务里直接 go func() { ... }。goroutine 轻量不等于免费——调度器要维护上下文、栈内存会增长、GC 压力随数量线性上升。
- HTTP 请求天然限流(连接数、超时、反向代理),单请求启一个 goroutine 通常安全
- 批量操作(如日志入库、通知推送)必须用
errgroup.Group或带缓冲 channel 控制并发上限,比如make(chan int, 10)限制同时最多 10 个 worker - 忘记加节流,10 万条数据直接起 10 万个 goroutine,轻则 OOM,重则调度器卡死
channel 关闭责任必须唯一,且只由发送方 close
框架中 channel 多用于解耦生产/消费逻辑(如中间件链、事件广播),但关闭时机错位会导致 panic 或死锁。
- 向已关闭的
ch发送数据:触发panic: send on closed channel - 接收方用
for range ch等待,但发送方忘了close(ch)→ 循环永不退出 - 多个发送方共用一个 channel?不行。要么改用
select+default非阻塞写,要么让每个 sender 自己管理子 channel - 典型做法:启动一个 goroutine 负责发送全部数据,发完后
close(ch);消费者只读,不关
context.Context 必须贯穿调用链,尤其涉及 I/O
框架里常见漏传 ctx 的地方:数据库查询、HTTP client 调用、文件读写、第三方 SDK。一旦漏传,超时和取消就失效。
-
db.QueryContext(ctx, ...)和http.Client.Do(req.WithContext(ctx))是硬性要求,不是可选项 - 自定义中间件或插件函数,参数列表第一项应是
ctx context.Context,避免下游无法控制生命周期 - 不要用
context.Background()替代传入的ctx,否则整个链路脱离父 cancel 控制 - time.AfterFunc、ticker 启动的 goroutine,必须用
ctx.Done()做退出守卫,否则长期驻留
竞态检测不能靠感觉,要开 -race 并进 CI
框架代码往往被多处复用,共享变量(如配置缓存、计数器、状态 flag)极易引发竞态,而本地测试很难复现。
- 开发阶段加
go run -race或go test -race,不是“等出问题再查” - sync.Mutex 只保护临界区,别把整个函数包进去;
atomic更适合标志位、计数器等简单场景 - 切忌用 channel 传大结构体——拷贝开销大,优先传指针或用
sync.Pool复用对象 - map 并发读写必 panic,读多写少用
sync.RWMutex,读写均衡考虑sync.Map(但注意它不保证迭代一致性)
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











