缓冲/非缓冲通道

huangapple go评论110阅读模式
英文:

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 &lt;- 3
}

fatal error: all goroutines are asleep - deadlock!

Buffered channel

package main

func main() {
   	c := make(chan int, 1)
    c &lt;- 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 &lt;- 3
    c &lt;- 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 &lt;-) to and someone who takes (&lt;- 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 &lt;- 3 }() // Create a new gorountine that puts 3 to the channel

fmt.Println(&lt;- 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&#39;s the reason why your problem is generated. Un-buffered channels are only writable when there&#39;s someone blocking to read from it, which means you shall have some coroutines to work with -- instead of this single one.

huangapple
  • 本文由 发表于 2014年1月12日 04:52:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/21067740.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定