本文详解 go 语言中向未缓冲 channel 发送数据时发生阻塞的根本原因,并提供两种可靠解决方式:启动 goroutine 实现并发收发,或使用带缓冲 channel 避免同步依赖。
本文详解 go 语言中向未缓冲 channel 发送数据时发生阻塞的根本原因,并提供两种可靠解决方式:启动 goroutine 实现并发收发,或使用带缓冲 channel 避免同步依赖。
在 Go 中,channel 是协程间通信的核心机制,但其行为高度依赖于缓冲类型与并发模型。原代码中 ch := make(chan bool) 创建的是一个未缓冲(unbuffered)channel,它要求发送(ch 同时就绪——即发送方和接收方需在不同 goroutine 中同步执行。而原程序仅有一个主线程(main goroutine),self.quack(ch) 在 MoneyDive() 中被同步调用,导致 ch
✅ 正确方案一:启用 goroutine 并发执行
将 quack 调用移至新 goroutine,使发送与接收可并行进行:
func (self *DagobertDuck) MoneyDive() {
ch := make(chan bool)
go self.quack(ch) // 启动新 goroutine 执行发送
b := <p>此时执行流程为:</p>
- 主 goroutine 创建 channel → 启动 mockQuack goroutine → 立即进入接收
- mockQuack goroutine 执行 ch
✅ 输出顺序:mockQuack start → mockQuack done → true
✅ 正确方案二:使用带缓冲 channel
若逻辑上无需严格并发,也可通过缓冲避免同步等待:
func (self *DagobertDuck) MoneyDive() {
ch := make(chan bool, 1) // 缓冲容量为 1,允许一次无接收的发送
self.quack(ch) // 同步调用,立即返回(因有缓冲空间)
fmt.Println(<p>注意:缓冲大小必须 ≥ 1 才能容纳发送值;若后续再次 ch </p><h3>⚠️ 关键注意事项</h3>
- 永远不要对 nil channel 发送或接收:会导致永久阻塞;
- 关闭已关闭的 channel 或向关闭 channel 发送:触发 panic;
- 过度依赖 channel 处理简单逻辑可能增加复杂度:如本例中 mockQuack() 完全可用 func() bool 替代,更简洁高效;
- fmt.Println(
掌握 channel 的阻塞特性与 goroutine 协作模式,是写出健壮、可维护 Go 并发代码的基础。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











