使用两个Goroutine打印1-100出现死锁,请求错误排查
问题分析与修复
你的代码触发死锁主要有三个核心问题:
1. 变量遮蔽导致全局通道未初始化
你声明了全局变量var my_chan chan int,但在main函数里又用my_chan := make(chan int)重新定义了局部变量——这导致两个worker协程实际调用的是未初始化的全局nil通道。nil通道的读写操作会永久阻塞,这是死锁的根源。
2. WaitGroup的Done调用不匹配
你调用了wg.Add(2),但只有当某个worker处理到number>100时才会调用一次wg.Done(),另一个worker会一直阻塞在number := <-my_chan的读取操作上,永远无法执行wg.Done(),最终wg.Wait()会无限等待,引发死锁。
3. 无缓冲通道的收尾阻塞
当number增加到100时,当前worker打印后number变成101,直接return,没有后续发送操作,但另一个worker还在等待读取通道,主协程也卡在wg.Wait(),所有协程进入休眠状态。
修复后的代码
package main import ( "fmt" "sync" ) var wg sync.WaitGroup func worker(ch chan int) { defer wg.Done() // 用defer确保协程退出时必触发Done for { number, ok := <-ch // 检查通道是否已关闭 if !ok { return } if number > 100 { close(ch) // 关闭通道通知其他worker退出 return } fmt.Println(number) ch <- number + 1 } } func main() { wg.Add(2) my_chan := make(chan int) go worker(my_chan) go worker(my_chan) my_chan <- 1 wg.Wait() }
修复说明:
- 去掉全局通道,改为将通道作为参数传递给worker,彻底避免变量遮蔽问题。
- 用
defer wg.Done()确保每个worker无论正常退出还是因通道关闭退出,都会通知WaitGroup,解决Done调用不匹配的问题。 - 当number超过100时关闭通道,让另一个worker通过
ok值判断通道状态,正常退出循环。
内容的提问来源于stack exchange,提问作者Ren
相关产品推荐
相关产品推荐

