环境:OS X 10.8,GO 1.0.2

我制作一个带有缓冲区2的频道,然后如果我写三次频道,它将引发错误:

投掷:所有goroutines都睡着了 - 僵局!

当然,这是正确的。

如果我在Goroutines中写四次或更多次频道,它可以正常工作,为什么?频道的容量是2,为什么goroutines忽略了它或忘记容量设置?我评论读取通道代码,因此没有人会阅读频道并节省容量。我还使用时间。睡觉等待所有goroutines完成他们的工作。

请查看以下代码:包装主

//import "fmt"

func main() {
    c := make(chan int, 2)
    /*c <- 1
    c <- 2
    c <- 3*/
    for i:=0; i<4; i++ {
        go func(i int) {
            c <- i
            c <- 9
            c <- 9
            c <- 9
        }(i)
    }
    time.Sleep(2000 * time.Millisecond)

    /*for i:=0; i<4*2; i++ {
        fmt.Println(<-c)
    }*/
}

有人请点击吗?多谢你们。

有帮助吗?

解决方案

当通道被缓冲时,这意味着在缓冲区已满之前,它不会阻止。一旦缓冲区填充,发送Goroutine将在尝试将其添加到频道中时阻塞。

这意味着这将阻止:

c := make(chan int)
c <- 1          // Block here, this is unbuffered !
println(<-c)

这将是 堵塞:

c := make(chan int, 2)
c <- 1
c <- 2
c <- 3           // Block here, buffer is full !
println(<-c)

但是 观点 Goroutines和渠道正是同时运行的,因此这将起作用:

c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c)            // ... this line is reached in the main goroutine

同样:

c := make(chan int, 2)
go func() {  // `go ...` spawns a goroutine
    c <- 1   // Buffer is not full, no block
    c <- 2   // Buffer is not full, no block
    c <- 3   // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine

在您的示例中,您产生了四个不同的goroutines,它们全部将四个数字写入同一缓冲通道。由于缓冲区为2 <16,他们最终会阻止

但是问题的症结在于,GO政策是 只等待主要的goroutine:

程序执行首先初始化主包,然后调用函数主。当功能主返回时,程序退出。它不会等待其他(非曼)goroutines完成。

这意味着在您的第一个示例中, 主要的 Goroutine到达线时正在封锁 c <- 3. 。由于没有其他Goroutine能够做任何可能取消阻止它的事情,因此运行时发现该程序已陷入僵局并报告了错误。

但是,在您的第二个示例中, 产卵 Goroutines Block,而主要的块一直静静地持续到达到其处决结束为止,此时,所有(封锁的)产卵的Goroutines被静静地杀死,并且没有报告任何错误。

其他提示

瓦尔 给出了一个很好的答案。我想添加一个额外的提示,我发现有用。

当学习使用Goroutines时,请使用零缓冲通道开始。这样,当您犯错时,您将立即陷入困境,您可以从中学习。您需要学习如何编写没有死锁的代码,这意味着学习技巧,例如在客户服务器关系中没有循环依赖性(假设您的goroutines是作为客户端或服务器写的)。

关于网络无需缓冲的推理更简单,尽管起初可能并不明显。

缓冲真的很有用,但应被视为提高性能的一种手段。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top