【问题标题】:Deadlock between goroutinesgoroutine 之间的死锁
【发布时间】:2017-04-09 01:10:28
【问题描述】:

我是 Go 新手。当我注释掉第二个 goroutine 时,出现了致命错误。我不明白是什么导致了这个错误的发生。能给我解释一下吗?

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    go func() { 
        for i := 0; i < 10; i++ {
            ch <- i
        }
    } ()
    // go func() { 
        for {
            if num, ok := <-ch; !ok {
                break
            } else {
                fmt.Printf("%d\n", num)
            }
        }
    // } ()
    time.Sleep(2 * time.Second)
    close(ch)
}

这将打印以下代码:

0
1
2
3
4
5
6
7
8
9
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
    /tmp/sandbox169127128/main.go:17 +0xa0

Program exited.

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    在接收到来自发送 goroutine 的所有值之后,接收来自 ch 的 for 循环阻塞。运行时检测到程序卡住并出现紧急情况。

    解决方法是在发送完所有值后关闭通道:

    go func() { 
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
    } ()
    

    在关闭的通道上接收会产生值0, false。接收 for 循环在 false 值上中断。

    从程序末尾删除close(ch)

    Run it on the playground.

    【讨论】:

    • 谢谢你简洁的解释,Cerise。我不确定我是否完全理解“阻塞”的概念。这是否意味着接收 for 循环永远等待?这是因为下面代码左侧的 ok 接收到 true,但永远不会有另一个 num 可以给出?如果 num, ok :=
    • @Pizzas: en.wikipedia.org/wiki/Blocking_(computing) 在您的情况下,num, ok := &lt;-ch 正在阻塞(等待另一个响应)。其他响应永远不会出现,因为发送 go 例程已经退出。如果您在发送 go 例程中关闭通道,则会收到另一个响应(指示通道已关闭)
    • @Pizzas 在打开的通道上接收等待将值发送到通道。在接收到来自发送 goroutine 的所有值之后,接收循环将永远等待。
    【解决方案2】:

    因为您没有在第一个 goroutine 退出之前关闭通道。下面的代码应该可以工作。

    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        ch := make(chan int)
        go func() { 
            for i := 0; i < 10; i++ {
                ch <- i
            }
            close(ch)
        } ()
        //go func() { 
            for {
                if num, ok := <-ch; !ok {
                    break
                } else {
                    fmt.Printf("%d\n", num)
                }
            }
        //} ()
        time.Sleep(2 * time.Second)
    }
    

    在这里试试:https://play.golang.org/p/OdxNqbaZmj

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-18
      • 1970-01-01
      • 1970-01-01
      • 2019-09-07
      • 2021-06-30
      • 2014-02-22
      • 1970-01-01
      相关资源
      最近更新 更多