为什么会陷入僵局?



我在Go Playground中运行此代码: https://play.golang.org/p/1gqgXZXDhsF 但它以死锁告终:

package main
import (
"fmt"
"time"
)
func createFakeReadData(r map[int]chan string, n int) {
for {
time.Sleep(time.Duration(n - 1) * time.Second)
r[n] <- string(n)
}
}
func log(l <-chan string) {
fmt.Println(<-l)
}
func main() {
logChan := make(chan string)
go log(logChan)
rChanMap := make(map[int]chan string)
rChanMap[5] = make(chan string)
rChanMap[6] = make(chan string)
rChanMap[7] = make(chan string)
rChanMap[8] = make(chan string)
go createFakeReadData(rChanMap, 5)
go createFakeReadData(rChanMap, 6)
go createFakeReadData(rChanMap, 7)
go createFakeReadData(rChanMap, 8)
for {
var f string
select {
case f = <-rChanMap[5]:
logChan <- f
case f = <-rChanMap[6]:
logChan <- f
case f = <-rChanMap[7]:
logChan <- f
case f = <-rChanMap[8]:
logChan <- f
}
}
}
fatal error: all goroutines are asleep - deadlock!

我有 5 个 goroutines 和一个 main 中的 select 语句,它控制其中的 4 个(读者(。第 5 个(记录器(只是坐下来等待在频道上向其发送任何内容。当 4 个读取器中的一个从通道获取输入时,它应该在 select 语句中触发"case",然后尝试将该数据发送到记录器通道。

我对去频道相当陌生。我了解什么是死锁以及可能发生的一些情况,尤其是在使用无缓冲通道时。但在我看来,这应该有效。

提前感谢您的帮助。

createFakeReadData无休止地将字符串发送到像rChanMap[5]这样的通道中。 但在log中,您只从输出通道接收一次:

func log(l <-chan string) {
fmt.Println(<-l)
}

由于您创建的所有通道都是无缓冲的,如果没有从输出通道接收 goroutinelogChan,其他 goroutines 将永远阻止尝试发送到它。

您可能希望将log函数更改为:

func log(l <-chan string) {
for m := range l {
fmt.Println(m)
}
}

这样,它将从通道接收,直到关闭。

顺便说一句,一些免费建议:

  1. string(n)没有将整数转换为字符串,请尝试搜索正确的方法
  2. 创建通道时,应考虑何时应该关闭它,在您的代码中没有通道关闭
  3. 详细了解缓冲通道和无缓冲通道之间的区别

最新更新