【问题标题】:Deadlock When using chan and sync.waitgroup使用 chan 和 sync.waitgroup 时的死锁
【发布时间】:2021-01-03 02:38:15
【问题描述】:

我目前正在学习 Go 中的并发性。我编写了一个简单的测试程序来练习 goroutines。但每当我执行此操作时,我都会收到一条错误消息,指出 fatal error: all goroutines are asleep - deadlock! 我不知道我做错了什么。有谁知道我怎样才能使这项工作按预期进行。任何帮助将不胜感激


import (
    "fmt"
    "sync"
    "time"
)

func slow(i int, cha chan int, wg *sync.WaitGroup) {
    fmt.Println("HI", i)
    time.Sleep(time.Second * 2)
    cha <- i * 2
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    values := make(chan int)
    for i := 1; i < 12; i++ {
        wg.Add(1)
        go slow(i, values, &wg)
    }
    wg.Wait()
    close(values)
}

编辑:当我尝试将频道设为缓冲频道时,它可以工作。不知道怎么弄的

【问题讨论】:

  • 您在unbuffered 中的频道,因此发送者会阻塞,直到接收者从中消费。由于没有从通道读取任何内容,因此您的 goroutine 卡在 cha &lt;- i * 2 上,而 main 卡在 wg.Wait() 上。请参观 Go 以了解基础知识。
  • 如果问题解决了,请注明。

标签: go concurrency channel goroutine


【解决方案1】:

您当前的程序无法运行,因为无缓冲通道没有消费者。另外,WaitGroupchannel 也不需要同时使用。

考虑下面的例子:

func slow(i int, cha chan int) {
  fmt.Println("HI", i)
  time.Sleep(time.Second * 2)
  cha <- i * 2
}

func main() {
  values := make(chan int)
  defer close(values)
  for i := 1; i < 12; i++ {
    go slow(i, values)
  }

  for i := 1; i < 12; i++ {
    fmt.Println(<-values)
  }
}

这样我们就可以有一个发送者 goroutine 并且可以在主函数中消费消息。

如果我们只是想确保所有的 goroutine 在 main 完成执行之前完成,我们可以像下面这样删除通道:

func slow(i int, wg *sync.WaitGroup) {
    fmt.Println("HI", i)
    time.Sleep(time.Second * 2)
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i < 12; i++ {
        wg.Add(1)
        go slow(i, &wg)
    }
    wg.Wait()
}

使用缓冲通道有效,因为在缓冲区填满之前将消息推送到通道不再阻塞。

【讨论】:

    猜你喜欢
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多