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

我确信对这种微不足道的情况有一个简单的解释,但我是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 <-在 agoroutine中使示例按预期运行


package main


import "fmt"


func main() {

    c := make(chan int)        

    go func(){

       c <- 1

    }()

    fmt.Println(<-c)

}

再说一遍,为什么?


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


手掌心
浏览 232回答 3
3回答

喵喵时光机

在无缓冲通道中写入通道不会发生,直到必须有一些接收器等待接收数据,这意味着在下面的例子中func main(){&nbsp; &nbsp; ch := make(chan int)&nbsp; &nbsp; ch <- 10&nbsp; &nbsp;/* Main routine is Blocked, because there is no routine to receive the value&nbsp; &nbsp;*/&nbsp; &nbsp; <- ch}现在如果我们有其他 goroutine,同样的原则适用func main(){&nbsp; ch :=make(chan int)&nbsp; go task(ch)&nbsp; ch <-10}func task(ch chan int){&nbsp; &nbsp;<- ch}这将起作用,因为任务例程正在等待数据被使用,然后写入发生到无缓冲通道。为了更清楚,让我们交换主函数中第二条和第三条语句的顺序。func main(){&nbsp; ch := make(chan int)&nbsp; ch <- 10&nbsp; &nbsp; &nbsp; &nbsp;/*Blocked: No routine is waiting for the data to be consumed from the channel */&nbsp; go task(ch)}这会导致死锁所以简而言之,只有当有一些例程等待从通道读取时才会写入无缓冲通道,否则写入操作将被永远阻塞并导致死锁。注意:相同的概念适用于缓冲通道,但在缓冲区已满之前不会阻止发送方,这意味着接收方不一定要与每个写操作同步。因此,如果我们有大小为 1 的缓冲通道,那么您上面提到的代码将起作用func main(){&nbsp; ch := make(chan int, 1) /*channel of size 1 */&nbsp; ch <-10&nbsp; /* Not blocked: can put the value in channel buffer */&nbsp; <- ch&nbsp;}但是如果我们给上面的例子写更多的值,那么就会发生死锁func main(){&nbsp; ch := make(chan int, 1) /*channel Buffer size 1 */&nbsp; ch <- 10&nbsp; ch <- 20 /*Blocked: Because Buffer size is already full and no one is waiting to recieve the Data&nbsp; from channel */&nbsp; <- ch&nbsp; <- ch}

芜湖不芜

在这个答案中,我将尝试解释错误消息,通过它我们可以稍微了解 go 在通道和 goroutines 方面的工作原理第一个例子是:package mainimport "fmt"func main() {&nbsp; &nbsp; c := make(chan int)&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; c <- 1&nbsp; &nbsp;&nbsp; &nbsp; fmt.Println(<-c)}错误信息是:fatal error: all goroutines are asleep - deadlock!在代码中,根本没有 goroutines(顺便说一句,这个错误是在运行时,而不是编译时)。当 go 运行此行时c <- 1,它希望确保通道中的消息将在某处(即<-c)收到。Go 不知道此时是否会收到频道。因此,go 将等待正在运行的 goroutine 完成,直到发生以下任一情况:所有的 goroutine 都完成了(睡着了)goroutine 之一尝试接收通道在第 1 种情况下,go 会出错并显示上面的消息,因为现在 go 知道 goroutine 无法接收通道并且它需要一个。在第 2 种情况下,程序将继续,因为现在知道收到了这个频道。这解释了 OP 示例中的成功案例。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go