代码之家  ›  专栏  ›  技术社区  ›  curiousengineer

缓冲通道并关闭

go
  •  -1
  • curiousengineer  · 技术社区  · 6 年前

    我有一段代码,我试图根据我如何将 close 电话和地点

    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)
    }
    

    我试着去理解和阅读关于这个的博客,但是仍然不能理解一些事情

    1. 当我把收盘价定在pos1时,效果很好。但我不知道为什么 它起作用了。缓冲区在任何给定位置都不能容纳超过2个元素 时间,所以当写入2个元素时,循环将阻塞,直到 主路由进行读取。但我想在 缓冲通道,范围函数必须事先知道有多少 必须关闭并遍历该通道的元素。为什么? 做 关闭 在这个职位上工作?
    2. 当我把它放在位置2时,它只打印2个元素,这是有意义的,但是为什么 for loop 在尝试向已关闭的通道写入更多元素时不引发异常?
    3. 当我在pos3关闭时,我得到一个异常 fatal error: all goroutines are asleep - deadlock! 尽管所有5个整数都打印出来了。为什么会这样?
    1 回复  |  直到 6 年前
        1
  •  4
  •   leaf bebop    6 年前

    但我认为要在缓冲通道上做一个范围,范围函数必须事先知道有多少元素要迭代,并且必须关闭该信道。

    这种假设是错误的,也是所有误解的根源。

    在通道上测距的行为在go规范中描述: https://golang.org/ref/spec#For_statements

    对于信道,产生的迭代值是在信道上被发送的连续值,直到信道被关闭。如果通道ISNIL,范围表达式永远阻塞。

    当对for语句求值并且该语句不需要知道元素数时,不需要关闭通道。

    所以,在你的代码中,当你 close 在pos1中,这确实是正确的方法。当你把它放在POS3中时,for循环等待要关闭的信道,这只能在for循环本身之后发生,所以它是一个死锁。

    关闭 在POS2是辆马车,行为有点棘手。它是 可能的 若要引发错误,则可能只输出两个数字。这是因为当通道在for循环之前关闭时,循环可以在没有块的情况下运行。 main() 返回。什么时候 主体() 返回,go程序结束。它是否引起一个错误仅仅取决于调度器是否切换到进程之间的GOOTONE,这是不能保证的。