doutian3269 2018-06-22 04:13
浏览 30
已采纳

缓冲通道并关闭

I have a snippet of code that I am trying to understand based on how I put the close call and the location

func main() {
    ch := make(chan int, 2)

    go func(ch chan int) {
        for i := 1; i <= 5; i++ {
            ch <- i
            fmt.Println("Func goroutine sends data: ", i)
        }
        //Pos1 - Works perfectly
        //close(ch)
    }(ch)

    fmt.Println("Main goroutine sleeps 2 seconds")
    time.Sleep(time.Second * 2)

    fmt.Println("Main goroutine begins receiving data")
    //Pos2 - Puts in only 2 ints 1 and 2 and then prints only that
    //close(ch)
    for d := range ch {
        fmt.Println("Main goroutine received data:", d)
    }
    //Pos3 - Throws fatal error
    close(ch)
}

I have been trying to understand and read blogs on this but not able to understand somethings still

  1. When I place the close at Pos1, it works fine. But I am not sure why it works. The buffer cannot hold more than 2 elements at any given time, so when 2 elements are written, the loop will block until the main routing does a read. But I thought to do a range over a buffered channel, the range function has to know beforehand how many elements to iterate over and for that channel must be closed. Why does close work at this position?
  2. When I put it as position 2, it prints only 2 elements which kind of makes sense but why is the for loop not throwing an exception when it is trying to write more elements to the channel that is closed?
  3. When I close at Pos3, I get an exception fatal error: all goroutines are asleep - deadlock! though all 5 ints are printed. Why is that?
  • 写回答

1条回答 默认 最新

  • dsk88199 2018-06-22 04:37
    关注

    But I thought to do a range over a buffered channel, the range function has to know beforehand how many elements to iterate over and for that channel must be closed. 

    That assumption is wrong and the root of all misunderstandings.

    The behavior of ranging over a channel is described in the Go Spec: https://golang.org/ref/spec#For_statements

    For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

    The channel does not need to be closed when the for statement is evaluated and the statement does not need to know number of elements.

    So, in your code, when you put close in Pos1, it is indeed the right way to do it. When you put it in Pos3, the for loop waits the channel to be closed, which can only happen after the for loop itself, so it is a deadlock.

    Putting close in Pos2 is buggy and the behavior is a little tricky. It is possible to raise an error, yet it is possible to just output two numbers. This is because when the channel is closed before the for loop, the loop can run without block and then main() returns. And when main() returns, the Go program ends. Whether it raises an error solely depends on if the scheduler switch to goroutine between the process, which is not guaranteed.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向