如何修复Go语言通道死锁?排查程序通道阻塞位置
问题分析与修复
阻塞原因
- 重复接收通道值:
calculator函数的select分支中,比如case <-secondChan后又执行returnChan <- (<-secondChan) *3,这要求从secondChan接收两次值,但main里只发送了一次2,第二次接收会永久阻塞,导致returnChan无数据返回,最终main中的<-r也跟着阻塞。 - 需求实现偏差:原需求是输出第一个通道数字的平方根,但代码里写的是平方运算,不符合要求。
- 单次监听限制:当前
select仅执行一次就退出,无法持续处理通道的后续输入,不符合持续响应的需求。
修复后的代码
package main import ( "fmt" "math" ) func main() { ch1, ch2 := make(chan int), make(chan int) stop := make(chan struct{}) r := calculator(ch1, ch2, stop) // 测试第二个通道 ch2 <- 2 fmt.Println(<-r) // 测试第一个通道 ch1 <- 9 fmt.Println(<-r) // 发送停止信号 stop <- struct{}{} } func calculator(firstChan <-chan int, secondChan <-chan int, stopChan <-chan struct{}) <-chan int { returnChan := make(chan int) go func() { defer close(returnChan) for { select { case num := <-firstChan: // 计算平方根,按需处理小数转整数的逻辑 returnChan <- int(math.Sqrt(float64(num))) case num := <-secondChan: returnChan <- num * 3 case <-stopChan: return } } }() return returnChan }
关键修复点
- 避免重复接收:在
case分支中直接将通道值接收至变量(num := <-firstChan),一次接收后直接使用变量计算,消除额外阻塞。 - 循环监听通道:用
for包裹select,让goroutine持续监听三个通道的输入,直到收到stop信号才退出。 - 修正平方根计算:使用
math.Sqrt函数实现需求中的平方根功能,处理好整数与浮点数的类型转换。 - 正确处理stop信号:收到stop信号后直接
return,配合defer close(returnChan)关闭返回通道,避免main侧出现不必要的阻塞。
内容的提问来源于stack exchange,提问作者Vadim
相关产品推荐
相关产品推荐

