启动 goroutine 必须配合 sync.waitgroup 等待其完成,否则主 goroutine 结束会导致子 goroutine 被强制终止;无缓冲 channel 发送前必须有接收方,否则发送操作阻塞。

goroutine 和 channel 是 Go 并发的两个基石,但它们不是“配好就能用”的积木——用错顺序、漏关 channel、混淆有/无缓冲行为,三分钟内就能触发死锁或 goroutine 泄露。
怎么启动一个真正能跑完的 goroutine
直接写 go f() 很容易让主函数退出后,新 goroutine 还没执行就全被杀掉。这不是 bug,是设计:Go 要求你显式管理生命周期。
- 主 goroutine 结束 → 所有其他 goroutine 强制终止(哪怕还在
fmt.Println中间) - 想等它做完?要么用
time.Sleep(仅限调试),要么用sync.WaitGroup -
WaitGroup必须在 goroutine 启动前调用wg.Add(1),且在 goroutine 内部结尾处调用wg.Done(),顺序反了会 panic
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done() // 保证无论是否 panic 都计数减一
fmt.Println("我跑完了")
}()
wg.Wait() // 阻塞直到 Done 被调用
为什么 ch := make(chan int) 一发就卡住
这是最典型的无缓冲 channel 阻塞:发送操作 ch 会一直等,直到另一个 goroutine 在同一时刻执行 <code> 接收——它本质是**同步握手**,不是队列。
- 无缓冲 channel = 0 容量,等同于
make(chan int, 0) - 如果你只在一个 goroutine 里又发又收,必然死锁(runtime error: all goroutines are asleep)
- 解法只有两个:① 确保收发在不同 goroutine;② 改用带缓冲 channel,如
make(chan int, 10)
ch := make(chan int, 1) // 缓冲为 1,可先发后收 ch <- 100 // 不阻塞 v := <-ch // 取出 100
什么时候必须 close(ch),不关会怎样
只有当 sender 明确“不会再发了”,才该调用 close;receiver 用 for range ch 时,close 是唯一安全退出方式。
本文档主要讲述的是android rtsp流媒体播放介绍;实时流协议(RTSP)是应用级协议,控制实时数据的发送。RTSP提供了一个可扩展框架,使实时数据,如音频与视频,的受控、点播成为可能。数据源包括现场数据与存储在剪辑中数据。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、组播UDP与TCP,提供途径,并为选择基于RTP上发送机制提供方法。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
立即学习“go语言免费学习笔记(深入)”;
- 不
close却用for range ch→ receiver 永远阻塞,goroutine 泄露 - 对已关闭的 channel 再 send → panic: send on closed channel
- 从已关闭的 channel 接收 → 返回零值 +
ok == false(不会 panic)
go func() {
for _, url := range urls {
ch <- url
}
close(ch) // 关键:告诉下游“数据发完了”
}()
// receiver 安全写法:
for url := range ch { // 自动在 close 后退出
fetch(url)
}
用 select 处理多个 channel 时的常见陷阱
select 不是轮询,而是随机选择一个就绪的 case;如果没有 case 就绪,且没有 default,就会永久阻塞。
- 忘加
default导致整个 goroutine 卡死(尤其在非关键路径上难排查) - 多个 channel 同时就绪时,选哪个是伪随机的,不能依赖顺序
-
select里的case语句必须是 channel 操作,不能是普通赋值或函数调用
select {
case msg := <-ch1:
handle(msg)
case <-done:
return // 退出 goroutine
default: // 防止阻塞,做点别的事(比如记录日志)
time.Sleep(10 * time.Millisecond)
}
真正麻烦的从来不是语法,而是谁负责关 channel、谁等谁、谁超时、谁 panic 后不清理资源——这些边界条件堆在一起,才是并发代码难维护的根源。









