go并发核心在于理解goroutine、channel与sync工具的协作边界:主goroutine提前退出会导致子goroutine未执行;用sync.waitgroup显式等待而非time.sleep;无缓冲channel需同步收发,关闭后可读不可写;for range ch需sender调用close;限并发用带缓冲channel作信号量。

Go 的并发模型不是靠“学语言”实现的,而是靠理解 goroutine、channel 和 sync 工具的协作边界与约束条件。
你不需要把 Go 语法全背下来才能写并发代码,但必须清楚:什么时候该用 chan、为什么 close 之后还能读、sync.WaitGroup 和 context.Context 到底管什么——这些不靠“学习语言”,靠动手时踩坑后反推。
goroutine 启动后立刻退出?检查主 goroutine 是否提前结束
常见错误是启动一堆 go f(),但主函数马上返回,整个进程退出,子 goroutine 根本没机会执行。
- 别靠
time.Sleep等待,它不可靠、难维护、易误判时长 - 用
sync.WaitGroup显式标记“哪些 goroutine 要等”:调用wg.Add(1)在 go 前,wg.Done()在 goroutine 结尾,最后wg.Wait() - 如果 goroutine 内部有阻塞操作(如从
chan读),而没人往里写,它会永远卡住——WaitGroup不会帮你发现这点
channel 阻塞或 panic?先分清缓冲类型和关闭时机
make(chan int) 是无缓冲 channel,发送和接收必须同步配对;make(chan int, 10) 是带缓冲的,能存 10 个值,但超了就阻塞。
- 向已关闭的
chan发送数据会 panic,但接收仍可继续,直到读完缓存 + 收到零值 - 多个 goroutine 从同一
chan读没问题,但多个 goroutine 往同一chan写,必须确保不会在关闭后还写 - 用
for range ch自动退出循环,前提是 sender 调用了close(ch);否则循环永不结束
如何限制并发数量?用带缓冲的 channel 当信号量,别硬控 goroutine 数量
直接起 1000 个 goroutine 请求 API,很可能打爆服务端或耗尽本地文件描述符。控制并发数不是“少起几个 goroutine”,而是“让它们排队拿令牌”。
- 声明
sem := make(chan struct{}, 5),容量为 5 就是最大并发数 - 每个 goroutine 开头写
sem ,满了就阻塞;结尾写 <code> 归还令牌 - 不要用
sync.Mutex控制计数器——它串行化竞争,违背并发初衷;channel 天然支持排队等待
超时与取消必须显式处理,context.Context 不是装饰品
没有 context.Context 的并发请求,一旦下游卡住,整个 goroutine 永远挂起,WaitGroup 等不到它,内存也收不回来。
- 所有可能阻塞的操作(
http.Client.Do、time.Sleep、chan读写)都应接受ctx参数并监听ctx.Done() -
ctx.WithTimeout或ctx.WithCancel创建新上下文,记得defer cancel()防泄漏 - 从
ctx.Done()接收到信号后,要主动清理资源(关 channel、释放锁、中断 IO),不能只 return
真正卡住人的从来不是语法,而是“某个 goroutine 在等一个永远不会来的值”或者“忘了 close 导致 range 永不退出”。写并发代码前,先画两秒流程图:谁发、谁收、谁关、谁等——比翻文档管用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











