golang通道死锁问题,我应该关闭通道

时间:2021-05-06 16:29:23

标签: go concurrency channel goroutine

package main

import (
    "fmt"
    "sync"
)

func main(){
    ch1 := make(chan int,100)
    ct := 0
    var wg sync.WaitGroup

    wg.Add(1)
    go func(){
        //defer close(ch1)
        for i:= 0; i < 10;i ++{
            ch1 <- i
        }
    }()

    go func(){
        defer wg.Done()
        for x := range ch1{
            fmt.Println(x)
        }
    }()
    wg.Wait()

    fmt.Println("numbers:",ct)
}

为什么这个代码会返回 fatal error: all goroutines are asleep - deadlock! 我发现如果我关闭通道不会有死锁,但我不知道为什么会这样。 把所有物品输入频道后,是否需要关闭频道?

3 个答案:

答案 0 :(得分:5)

通道上的

for range 仅在 / 当通道关闭时终止。如果您不关闭通道并且不向其发送更多值,则 for range 语句将永远阻塞,main 处的 wg.Wait() 协程也将如此。

“发送方”发送完所有值后应关闭通道,向“接收方”方发出信号,表示通道上将不再有值。

所以是的,你应该关闭频道:

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

答案 1 :(得分:0)

从通道读取的 for 循环将继续读取,除非您关闭通道。这就是死锁的原因,因为从通道读取的 goroutine 是唯一活动的 goroutine,并且没有其他 goroutine 可以写入它。当您关闭时,for 循环终止。

答案 2 :(得分:0)

  1. range unclosed ch1 会导致阻塞;
  2. 即使关闭ch1,仍然可以从ch1接收数据;
  3. 可以说,close(ch1)会向ch1发送一条特殊的消息,可以用来通知ch1接收方不再接收数据。所以即使ch1中有数据,也可以通过close()方法,而不会导致接收方收不到剩余数据。
  4. 通道不需要通过close释放资源。只要没有 goroutine 持有通道,就会自动释放相关资源。 取消注释 defer close(ch1) 将解决这个问题。 here
相关问题