【问题标题】:Understanding golang channels: deadlock了解 golang 通道:死锁
【发布时间】:2019-05-10 06:35:07
【问题描述】:

以下代码:

package main

import (
    "fmt"
    "strings"
)

var data = []string{
    "The yellow fish swims slowly in the water",
    "The brown dog barks loudly after a drink ...",
    "The dark bird bird of prey lands on a small ...",
}

func main() {
    histogram := make(map[string]int)
    words := make(chan string)

    for _, line := range data {
        go func(l string) {
            for _, w := range strings.Split(line, " ") {
                words <- w
            }
        }(line)
    }

    defer close(words)
    for w := range words {
        histogram[w]++
    }

    fmt.Println(histogram)
}

以死锁结束:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
    /tmp/sandbox780076580/main.go:28 +0x1e0

我的理解是频道词会阻塞作者和读者以达到一些同步。我正在尝试为所有 goroutines(编写器)和 main 中的单个读取器(使用“range”命令)使用单个通道。 我也尝试过缓冲通道 - 类似的失败。 我很难理解为什么这不起作用。有什么理解技巧吗?
谢谢。

【问题讨论】:

  • 延迟调用在周围函数退出时执行。当通道关闭时,通道上的范围循环退出。由于您试图在 main 的退出处关闭通道,因此通道上的范围循环永远不会退出,因此 main 也不会退出。 X 正在等待 Y 发生,而 Y 正在等待 X 发生。

标签: go deadlock


【解决方案1】:

正如问题的 cmets 中所述,在 main 返回之前不会执行延迟。因此,words 上的范围将永远阻塞。

要解决此问题,应用程序必须在所有 goroutine 发送完毕后关闭 words。一种方法是使用wait group。等待组为每个 goroutine 增加,当 goroutines 退出时减少。另一个 goroutine 等待该组并关闭通道。

func main() {
    histogram := make(map[string]int)
    words := make(chan string)

    var wg sync.WaitGroup
    for _, line := range data {
        wg.Add(1)
        go func(l string) {
            for _, w := range strings.Split(l, " ") {
                words <- w
            }
            wg.Done()
        }(line)
    }

    go func() {
        wg.Wait()
        close(words)
    }()

    for w := range words {
        histogram[w]++
    }

    fmt.Println(histogram)
}

奖励修复:问题中的 goroutine 引用了循环变量 iine 而不是参数 l。常见问题解答explains why this is a problem。

【讨论】:

猜你喜欢
  • 2018-02-02
  • 2021-01-03
  • 2020-01-24
  • 2017-10-05
  • 2021-03-26
  • 2020-07-16
  • 2011-08-24
  • 1970-01-01
  • 2019-04-05
相关资源
最近更新 更多