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

为什么没有接收器被阻塞的错误?

为什么没有接收器被阻塞的错误?

Go
噜噜哒 2022-05-05 17:36:20
根据Go 文档:接收器总是阻塞直到有数据接收此测试应该失败,因为对于来自通道的最后接收操作,没有相应的 write :package mainimport "fmt"func main() {    c := make(chan int)        for i := 0; i < 4; i++ { // 4 async reads      go func() {            fmt.Println("received:", <-c)         }()    }        // just 3 writes, 1 write is missing    c <- 1       c <- 2     c <- 3   }但是脚本在读取 goroutine 中没有失败并显示错误消息,但它成功打印了 3 个值:收到:1收到:2收到:3为什么会这样,或者我对同步有误解?
查看完整描述

1 回答

?
弑天下

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

这里没有死锁,因为maingoroutine 没有被阻塞。它发送 3 个c成功的值,因为有 4 个启动的 goroutine 从它接收,然后它结束。它也会结束你的应用程序,它不会等待其他非maingoroutine 结束。请参阅goroutine 无输出。


死锁意味着所有 goroutine 都被阻塞。这不是这里的情况。


尝试从没有人(当前或曾经)准备发送的通道接收不是错误。如果是事实,那是完全正常的。这是通道的用例之一:它充当同步工具,您可以发送/接收,并且操作将阻塞,直到另一端也准备好。


在某些情况下,即使是在整个应用程序生命周期内阻塞的 goroutine 也是正常的,例如,goroutine 可能会等待用户输入(例如CTRL+ BREAK),用户可能永远不会按下并且应用程序可能会正常结束。


所以这不被认为是错误,并且不会为这些打印错误或警告消息。但是如果你很好奇,它很容易实现。只需向您的函数添加一个延迟函数,该函数将在您的函数(以及您的应用程序)结束main()之前被调用。main()在该打印中运行的 goroutine 的数量:


func main() {

    defer func() {

        fmt.Println("Remaining goroutines:", runtime.NumGoroutine()-1) //-1 for main

    }()


    // your code

}

加上这个,输出将是:


received: 1

received: 2

received: 3

Remaining goroutines: 1

如果您将循环更改为启动 14 个 goroutine 而不是 1 个,输出将显示剩余 11 个 goroutine。


最后一点:由于在您的应用程序中,该main()函数不会等待其他 goroutine 结束,因此在调用延迟函数时它们可能仍然处于活动状态,因此它们可能会或可能不会包含在剩余的 goroutine 计数中。如果您使用 egsync.WaitGroup来等待它们结束,那么它们肯定不会被包括在内。有关示例,请参见在 Golang 中的 goroutines 完成之前阻止 main() 函数终止。


查看完整回答
反对 回复 2022-05-05
  • 1 回答
  • 0 关注
  • 126 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号