小编典典

为什么在同一goroutine中使用未缓冲的通道会导致死锁?

go

我敢肯定对这种琐碎的情况有一个简单的解释,但是我对go并发模型是陌生的。

当我运行这个例子

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使示例按预期运行

package main

import "fmt"

func main() {
    c := make(chan int)        
    go func(){
       c <- 1
    }()
    fmt.Println(<-c)
}

再次,为什么?

请,我需要深入的解释,而不仅仅是如何消除死锁并修复代码。


阅读 260

收藏
2020-07-02

共1个答案

小编典典

文档中

如果通道未缓冲,则发送方将阻塞,直到接收方收到该值为止。如果通道具有缓冲区,则发送方仅阻塞该值,直到将值复制到该缓冲区为止;否则,发送方才阻塞。如果缓冲区已满,则意味着要等到某些接收器检索到一个值。

否则说:

  • 当频道已满时,发送方等待另一个goroutine通过接收来腾出空间
  • 您会看到一个未缓冲的通道总是一个完整的通道:必须有另一个goroutine来处理发送方发送的内容。

这条线

c <- 1

阻塞,因为通道没有缓冲。由于没有其他goroutine可以接收该值,因此情况无法解决,这是一个僵局。

您可以将频道创建更改为

c := make(chan int, 1)

这样,频道在被阻止之前就可以容纳一个项目。

但这不是并发的意义所在。通常,没有其他goroutine不会使用通道来处理放入内部的内容。您可以这样定义一个接收goroutine:

func main() {
    c := make(chan int)    
    go func() {
        fmt.Println("received:", <-c)
    }()
    c <- 1   
}

示范

2020-07-02