2 回答
TA贡献1827条经验 获得超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)
但是,点够程和渠道的恰恰是跑的东西兼任,所以这将工作:
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 能够做任何可能解除阻塞的事情,运行时检测到程序死锁并报告错误。
但是,在您的第二个示例中,生成的goroutine 会阻塞,而 main 会安静地继续运行,直到执行结束,此时所有(被阻止的)生成的 goroutine 都会被悄悄杀死,并且不会报告任何错误。
TA贡献1942条经验 获得超3个赞
在学习使用 goroutines 时,首先使用零缓冲通道。这样,当你犯错时,你会立即陷入僵局,你可以从中吸取教训。你需要学习如何编写不会死锁的代码,这意味着学习一些技巧,比如在客户端 - 服务器关系中没有循环依赖(假设你的 goroutine 是作为客户端或服务器编写的)。
关于没有缓冲的网络的推理更简单,尽管一开始这可能并不明显。
缓冲确实很有用,但应被视为提高性能的一种手段。
- 2 回答
- 0 关注
- 213 浏览
添加回答
举报