为了账号安全,请及时绑定邮箱和手机立即绑定

golang 通道在接收值之前死锁

golang 通道在接收值之前死锁

Go
慕妹3242003 2023-06-01 18:09:10
我不明白为什么这不起作用https://play.golang.org/p/_ALPii0pXV6但这个https://play.golang.org/p/vCOjAr-o54e有效。据我了解,goroutine 异步发送值 true 到 a 和 12 到 b。在 main 函数中, a 被阻塞,直到它接收到一个值。为什么当我重新安排它使 b 在 a 之前被阻塞时,会导致死锁?
查看完整描述

3 回答

?
撒科打诨

TA贡献1934条经验 获得超2个赞

默认情况下,Go 通道是无缓冲的。这意味着在接收方读取通道之前,它不能在通道上发送。这实际上是 Go 的首选模式。在大多数情况下,它比缓冲通道更有效。

这对您的第一个代码意味着 goroutine 在完成对通道 a 的写入之前无法继续写入通道 b。在主 goroutine 读取 a 之前,它不能这样做。


查看完整回答
反对 回复 2023-06-01
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

默认情况下,通道发送和接收会等待发送例程和接收例程都准备就绪。通过以下示例可以明显看出这种阻塞:

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

这段代码会导致死锁,因为唯一的 goroutine(主协程)卡在ch <- 1,等待另一个 goroutine 接收。它几乎不知道我们期望它成为下一行的接收者。

这解释了为什么您的第一个示例不起作用,因为另一个 goroutineb在其发送操作a完成之前不会发送。a但是主例程在收到之前不会收到b!所以两者都永远等待着。

查看完整回答
反对 回复 2023-06-01
?
料青山看我应如是

TA贡献1772条经验 获得超8个赞

如果您按照顺序执行的方式重写代码,那么发生的事情就会变得更加清晰。


原始代码:


func main() {

    a := make(chan bool)

    b := make(chan int64)

    go func(a chan bool, b chan int64) {

        fmt.Println("Here1")

        a <- true

        b <- 12

    } (a,b)

    fmt.Println("Here2")

    fmt.Println(fmt.Sprintf("%d", <-b))

    fmt.Println(fmt.Sprintf("%v", <-a))

}

相同代码顺序执行的紧密表示:



    a := make(chan bool)

    b := make(chan int64)

    fmt.Println("Here2") // Prints


    // Pass control to new goroutine

    fmt.Println("Here1")

    a <- true     // Write to channel a and block goroutine here and pass control to main


    fmt.Println(fmt.Sprintf("%d", <-b)) // Tries to read from b but nothing has been written to it so blocks. At this point all your goroutines are blocked hence the deadlock.


    fmt.Println(fmt.Sprintf("%v", <-a)) // doesn't even reach here.

    b <- 12

}


查看完整回答
反对 回复 2023-06-01
  • 3 回答
  • 0 关注
  • 144 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信