问题描述
我确信对这种微不足道的情况有一个简单的解释,但我是 go
并发模型的新手.
I'm sure that there is a simple explanation to this trivial situation, but I'm new to the go
concurrency model.
当我运行这个例子时
package main
import "fmt"
func main() {
c := make(chan int)
c <- 1
fmt.Println(<-c)
}
我收到此错误:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/tarrsalah/src/go/src/github.com/tarrsalah/tour.golang.org/65.go:8 +0x52
exit status 2
为什么?
将 c <-
包裹在 goroutine
中使示例按预期运行
Wrapping c <-
in a goroutine
makes the example run as we expected
package main
import "fmt"
func main() {
c := make(chan int)
go func(){
c <- 1
}()
fmt.Println(<-c)
}
再说一遍,为什么?
拜托,我需要深入的解释,而不仅仅是如何消除死锁和修复代码.
Please, I need deep explanation , not just how to eliminate the deadlock and fix the code.
推荐答案
来自文档 :
如果通道未缓冲,则发送方会阻塞,直到接收方收到该值.如果通道有缓冲区,则发送方只会阻塞直到值已复制到缓冲区;如果缓冲区已满,这意味着等待直到某个接收者检索到一个值.
另有说法:
- 当一个通道已满时,发送者等待另一个 goroutine 通过接收来腾出空间
- 你可以看到一个无缓冲的通道总是满的:必须有另一个 goroutine 来接收发送者发送的内容.
这一行
c <- 1
阻塞,因为通道没有缓冲.由于没有其他goroutine来接收值,这种情况无法解决,这是一个死锁.
blocks because the channel is unbuffered. As there's no other goroutine to receive the value, the situation can't resolve, this is a deadlock.
您可以通过将频道创建更改为不阻塞
You can make it not blocking by changing the channel creation to
c := make(chan int, 1)
以便在频道中的一个项目被阻塞之前有空间.
so that there's room for one item in the channel before it blocks.
但这不是并发的意义所在.通常,您不会在没有其他 goroutine 的情况下使用通道来处理您放入的内容.你可以像这样定义一个接收 goroutine :
But that's not what concurrency is about. Normally, you wouldn't use a channel without other goroutines to handle what you put inside. You could define a receiving goroutine like this :
func main() {
c := make(chan int)
go func() {
fmt.Println("received:", <-c)
}()
c <- 1
}
这篇关于为什么在同一个 goroutine 中使用无缓冲通道会导致死锁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!