go - 为什么会陷入僵局?

标签 go deadlock channel goroutine

我在 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!

我在 main 中有 5 个 goroutine 和一个 select 语句,控制其中的 4 个(读者)。第 5 个(记录器)只是坐下来等待任何内容通过 channel 发送给它。当 4 个读取器中的一个从 channel 获取输入时,它应该在 select 语句中触发“案例”,然后尝试将该数据向前发送到记录器 channel 。

我很新去 channel 。我了解什么是死锁以及可能发生的某些情况,尤其是在使用无缓冲 channel 时。但这在我看来应该可行。

在此先感谢您的帮助。

最佳答案

createFakeReadData将字符串无休止地发送到 rChanMap[5] 等 channel 中.
但是在 log您只能从输出 channel 接收一次:

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

由于您创建的所有 channel 都是无缓冲的,如果没有从输出 channel 接收 goroutine logChan ,其他 goroutine 将永远阻止尝试发送给它。

您可能想要更改 log功能如下:
func log(l <-chan string) {
    for m := range l {
        fmt.Println(m)
    }
}

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

顺便说一句,一些免费的建议:
  • string(n)不会将整数转换为字符串,请尝试搜索正确的方法来执行此操作
  • 当你创建一个 channel 时,你应该考虑什么时候应该关闭它,在你的代码中没有 channel 被关闭
  • 详细了解缓冲 channel 和非缓冲 channel 之间的区别
  • 关于go - 为什么会陷入僵局?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59331267/

    相关文章:

    go - 如何在没有 gopath 的情况下导入本地包

    go - 是否有任何标准库可以将 float64 转换为具有固定宽度和最大有效位数的字符串?

    go - Golang 中的 TF-IDF

    MySQL死锁问题

    go - 了解 golang channel : deadlock

    java - 如何使用 AsynchronousServerSocketChannel 绑定(bind)多个端口?

    arrays - 数组数组中特定位置的类型?

    戈朗 : Learning goroutine took me to a deadlock

    go - 合并两个关闭 channel

    go - 如何从 goroutine 结束一个 go 程序