尝试使用'range'打印通道值后出现死锁

时间:2015-01-25 19:25:34

标签: go channel goroutine

以下是Go Playground

的代码
package main

import (
    "fmt"
)

func sum_up(my_int int, cs chan int) {
    my_sum := 0
    for i := 0; i < my_int; i++ {
        my_sum += i
    }
    cs <- my_sum
}

func main() {

    my_channel := make(chan int)
    for i := 2; i < 5; i++ { 
        go sum_up(i, my_channel)
    }


    for ele := range my_channel {
        fmt.Println(ele)
    }  

    //fatal error: all goroutines are asleep - deadlock!

    fmt.Println("Done")

}

结果是:

1
3
6
fatal error: all goroutines are asleep - deadlock!

我不明白导致错误的原因。我的理解是,在我的函数sum_up中,我向my_channel添加了新值。为什么在我尝试打印出值后会出现问题?由于我看到1,3,6被打印,这意味着所有goroutines都已成功完成。

此外,如果试图打印通道值的块

    for ele := range my_channel {
        fmt.Println(ele)
    }

被删除,然后我没有收到错误。所以它包含导致错误的块,但为什么呢?

3 个答案:

答案 0 :(得分:3)

空信道上的for-range将被阻塞,直到有信息从信道读取或直到信道关闭为止。

这是一个使用sync.WaitGroup来说明有多少goroutine保持活动状态的版本。完成所有goroutine后,通道关闭,并且存在for-range循环。

https://play.golang.org/p/ZnLYxLMNdF

package main

import (
    "fmt"
    "sync"
)

func sum_up(my_int int, cs chan int, wg *sync.WaitGroup) {
    my_sum := 0
    for i := 0; i < my_int; i++ {
        my_sum += i
    }
    cs <- my_sum
    wg.Done()
}

func main() {
    wg := &sync.WaitGroup{}
    my_channel := make(chan int)
    for i := 2; i < 5; i++ {
        wg.Add(1)
        go sum_up(i, my_channel, wg)
    }

    // Run a goroutine that will monitor how many sum_up are running.
    go func(cs chan int, wg *sync.WaitGroup) {
        wg.Wait()
        close(cs)
    }(my_channel, wg)

    for ele := range my_channel {
        fmt.Println(ele)
    }

    //fatal error: all goroutines are asleep - deadlock!

    fmt.Println("Done")

}

答案 1 :(得分:2)

在频道上使用range时,它会一直等待值或直到频道关闭。它的死锁是因为当最后一个值写入my_channel时,它将永远等待一个永远不会到来的值。

这是一个略有修改的变体,展示如何干净地离开范围:https://play.golang.org/p/YDlM8EcRnx

答案 2 :(得分:0)

当chan接收到关闭信号时,

for range chan退出。你必须在某个地方close(my_channel),否则循环将永远等待。