2

环境:OS X 10.8,Go 1.0.2

我创建了一个缓冲区大小为 2 的通道,然后如果我写入通道 3 次,它会抛出错误:

throw:所有的 goroutine 都处于休眠状态——死锁!

当然,这是正确的。

但是如果我在 goroutines 中写了四次或更多次通道,它工作正常,为什么?通道的容量是 2,为什么 goroutines 忽略了或者忘记了容量设置?我注释了读取通道代码,因此没有人会读取通道并节省容量。我也使用 time.Sleep 来等待所有 goroutine 完成它们的工作。

请查看以下代码: package main

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

有人可以打一些吗?多谢你们。

4

2 回答 2

8

当一个通道被缓冲时,这意味着它不会阻塞,直到缓冲区已满。一旦缓冲区已满,发送 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 和 channel 的重点恰恰是并发运行,所以这将起作用:

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

在您的示例中,您生成了四个不同的 goroutine,它们都将四个数字写入同一个缓冲通道。由于缓冲区是 2 < 16,它们最终会阻塞

但问题的关键在于 Go 的策略是只等待主 goroutine

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

这意味着在您的第一个示例中,goroutine 在到达 line 时被阻塞c <- 3。由于没有其他 goroutine 能够执行任何可能解除阻塞的操作,因此运行时检测到程序已死锁并报告错误。

然而,在您的第二个示例中,生成的 goroutines 阻塞,而 main 安静地继续直到它执行结束,此时所有(阻塞的)生成的 goroutines 都被静默杀死,并且没有报告错误。

于 2013-11-07T11:26:51.290 回答
1

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

在学习使用 goroutine 时,首先使用零缓冲通道。这样,当你犯错时,你会立即陷入僵局,你可以从中吸取教训。您需要学习如何编写不会死锁的代码,这意味着要学习一些技巧,例如在客户端-服务器关系中不存在循环依赖(假设您的 goroutine 被编写为客户端或服务器)。

在没有缓冲的情况下推理网络更简单,尽管起初这可能并不明显。

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

于 2013-11-09T23:31:50.163 回答