英文:
Buffered/Unbuffered channel
问题
有人可以解释一下,为什么如果通道是带缓冲的,程序不会因为致命错误而退出吗?
无缓冲通道
package main
func main() {
c := make(chan int)
c <- 3
}
致命错误:所有的goroutine都处于休眠状态 - 死锁!
带缓冲通道
package main
func main() {
c := make(chan int, 1)
c <- 3
}
[无输出]
程序已退出。
谢谢!
英文:
Could someone explain, why if the channel is buffered the program doesn't exit with a fatal_error?
Unbuffered channel
package main
func main() {
c := make(chan int)
c <- 3
}
fatal error: all goroutines are asleep - deadlock!
Buffered channel
package main
func main() {
c := make(chan int, 1)
c <- 3
}
[no output]
Program exited.
Thank you!
答案1
得分: 11
写入缓冲通道不会阻塞,如果缓冲区有空间的话。
如果你尝试将两个项目放入缓冲大小为1的通道中,你会得到相同的错误:
package main
func main() {
c := make(chan int, 1)
c <- 3
c <- 4
}
会得到以下错误信息:
fatal error: all goroutines are asleep - deadlock!
英文:
Writing to a buffered channel doesn't block if there is room in the buffer.
If you try to put two items in the channel with a buffer size of one, you get the same error:
package main
func main() {
c := make(chan int, 1)
c <- 3
c <- 4
}
gives you:
fatal error: all goroutines are asleep - deadlock!
答案2
得分: 4
这是Go语言中通道的核心概念(或其他CSP实现,如Clojure的core.async库):它们是阻塞的。一般来说,正如你已经提到的,通道有两种类型:
- 有缓冲的,如果缓冲区已满,则会阻塞。
- 无缓冲的,如果没有“会合”,即必须有人向通道中放入数据(
c <-
),同时有人从通道中取出数据(<- c
),则会阻塞。
在你的特定情况下,Go运行时聪明地检测到没有人会从通道c
中取出3
。因此,这是一个死锁,并且(幸运的是)会抛出错误。
当你使用通道时,通常会使用goroutine(请查看这个介绍),它会创建一个由Go运行时管理的轻量级线程来并发执行代码块:
c := make(chan int)
go func() { c <- 3 }() // 创建一个新的goroutine,将3放入通道中
fmt.Println(<-c) // 从通道中取出3并在主线程中打印
以上是要翻译的内容。
英文:
It's a core concept of Go's channels (or other CSP implementations such as Clojure's core.async library) that they are blocking. In general, as you already mentioned, there're two types of channels:
- buffered which block if the buffer is full.
- unbuffered which block if there's no "rendezvous", i.e. there must be someone who puts (
c <-
) to and someone who takes (<- c
) from the channel.
In your particular case the Go runtime is smart enough to detect that there's no one who will ever take 3
from channel c
. Hence, it's a deadlock and (thankfully) an error is thrown.
What you typically do when you're working with channels is using goroutines (checkout this introduction) which spawn a lightweight thread—managed by the Go runtime—to execute the body concurrently:
c := make(chan int)
go func() { c <- 3 }() // Create a new gorountine that puts 3 to the channel
fmt.Println(<- c) // Take 3 from the channel and print it in the main thread
答案3
得分: 2
感谢 @Matt
我在这篇帖子中找到了答案 How does make(chan bool) behave differently from make(chan bool, 1)? :
“实际上,这就是为什么会出现你的问题的原因。无缓冲通道只有在有人阻塞读取时才能写入,这意味着你应该有一些协程来处理它,而不是只有一个。”
英文:
Thanks @Matt
I found the answer in this post How does make(chan bool) behave differently from make(chan bool, 1)? :
Actually that's the reason why your problem is generated. Un-buffered channels are only writable when there's someone blocking to read from it, which means you shall have some coroutines to work with -- instead of this single one.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论