猿问

gorouines 是否忽略通道的缓冲区大小

环境:OS X 10.8,Go 1.0.2


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


throw:所有的 goroutine 都睡着了——死锁!


当然,这是正确的。


但是如果我在 goroutines 中写了四次或更多次通道,它工作正常,为什么?通道的容量是 2,为什么 goroutine 会忽略或忘记容量设置?我注释了读取通道代码,因此没有人会读取通道并节省容量。我也使用 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)

    }*/

}

有人可以给一些点击吗?谢谢你们。


呼唤远方
浏览 214回答 2
2回答

斯蒂芬大帝

当一个通道被缓冲时,这意味着它不会阻塞直到缓冲区已满。一旦缓冲区已满,发送 goroutine 将在尝试向通道添加内容时阻塞。这意味着这将阻止:c := make(chan int)c <- 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Block here, this is unbuffered !println(<-c)这将也阻止:c := make(chan int, 2)c <- 1c <- 2c <- 3&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Block here, buffer is full !println(<-c)但是,点够程和渠道的恰恰是跑的东西兼任,所以这将工作:c := make(chan int)go func() { c <- 1; }() // This will block in the spawned goroutine until...println(<-c)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // ... this line is reached in the main goroutine同样:c := make(chan int, 2)go func() {&nbsp; // `go ...` spawns a goroutine&nbsp; &nbsp; c <- 1&nbsp; &nbsp;// Buffer is not full, no block&nbsp; &nbsp; c <- 2&nbsp; &nbsp;// Buffer is not full, no block&nbsp; &nbsp; c <- 3&nbsp; &nbsp;// 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 能够做任何可能解除阻塞的事情,运行时检测到程序死锁并报告错误。但是,在您的第二个示例中,生成的goroutine 会阻塞,而 main 会安静地继续运行,直到执行结束,此时所有(被阻止的)生成的 goroutine 都会被悄悄杀死,并且不会报告任何错误。

手掌心

在学习使用 goroutines 时,首先使用零缓冲通道。这样,当你犯错时,你会立即陷入僵局,你可以从中吸取教训。你需要学习如何编写不会死锁的代码,这意味着学习一些技巧,比如在客户端 - 服务器关系中没有循环依赖(假设你的 goroutine 是作为客户端或服务器编写的)。关于没有缓冲的网络的推理更简单,尽管一开始这可能并不明显。缓冲确实很有用,但应被视为提高性能的一种手段。
随时随地看视频慕课网APP

相关分类

Go
我要回答