个人学习使用,此博客由Copilot生成。
Go 语言 Channel 的 <-ch
用法与同步场景总结
在 Go 语言中,<-
是 Channel(通道)操作符,通常用于数据的发送和接收。本文总结了 <-ch
的典型用法、常见问题和实际同步场景,适合归档查阅。
1. <-ch
的基本含义
<-ch
表示“从 channelch
接收一个值”。- 常见用法:
x := <-ch
:从 channel 接收值并赋值给x
。<-ch
:从 channel 接收值但不使用,常用于同步或等待信号。
2. 典型用法举例
ch := make(chan int)
go func() {
ch <- 10 // 向通道发送 10
}()
x := <-ch // 接收值并赋给 x,x == 10
<-ch // 仅接收值但不处理,常用于同步
3. 会不会出现空指针(nil)情况?
ch 为 nil 的情况
var ch chan int // 没有 make,ch 是 nil
<-ch // 会发生什么?
- 结果:会导致当前 goroutine 永久阻塞(deadlock),不会 panic,也不会出现“空指针异常”,但会让程序卡住。
已 make 但无数据
ch := make(chan int)
<-ch // 阻塞,直到有数据可读
- 结果:阻塞,不会 panic。
已关闭的 channel
ch := make(chan int, 1)
ch <- 10
close(ch)
v, ok := <-ch // v=10, ok=true
v, ok := <-ch // v=0, ok=false,通道已关闭且无数据
- 结果:不会 panic,读到零值和 false。
小结
- nil channel:
<-ch
永久阻塞,不 panic。 - 已初始化 channel 无数据:阻塞,不 panic。
- 关闭的 channel:返回零值,不 panic。
- Go 没有传统“空指针异常”,但 nil channel 阻塞是常见 bug。
4. <-ch
用于同步/阻塞的典型场景
<-ch
仅用于同步或阻塞,值被丢弃。典型场景是等待某个 goroutine 完成,只关心信号,不关心内容。
示例一:单个 goroutine 完成信号
func main() {
done := make(chan struct{})
go func() {
// ...做一些工作
done <- struct{}{} // 发送信号
}()
<-done // 阻塞等待信号,值丢弃
println("main received done signal")
}
chan struct{}
:零内存,适合只做信号同步。<-done
用于阻塞主流程,直到 goroutine 完成。
示例二:等待多个 goroutine 完成
func main() {
done := make(chan struct{})
for i := 0; i < 3; i++ {
go func(i int) {
// ...做一些工作
done <- struct{}{}
}(i)
}
// 等待全部 goroutine 完成
for i := 0; i < 3; i++ {
<-done // 阻塞多次,丢弃信号
}
println("all goroutines done")
}
- 多个 goroutine 都往同一个 channel 发送信号,主流程用
<-done
多次等待全部完成。
5. 实践建议
- 只需等待信号、无需数据时,推荐用
chan struct{}
,配合<-ch
。 - 并发较复杂时建议用
sync.WaitGroup
,其本质也是信号同步,但更易用。 - 若 channel 可能为 nil,建议提前判断:
if ch != nil {
<-ch
}
6. 总结
<-ch
是 Go 并发同步的基础手段,无论是收数据还是仅同步。- nil channel 导致阻塞是常见陷阱,需注意初始化。
<-ch
丢弃值的用法,常见于 goroutine 同步、信号通知等场景。
参考资料: