根据Go documentation :
Receivers always block until there is data to receive
此测试应该失败,因为对于来自 channel 的最后接收操作,没有相应的 write :
package main
import "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
为什么会这样,或者我对同步有误解?
最佳答案
这里没有死锁,因为 main
goroutine 没有被阻塞。它在 c
上发送 3 个值成功是因为有 4 个已启动的 goroutine 从它接收,然后它结束。并且它也会结束您的应用程序,它不会等待其他非 main
goroutines 结束。见 No output from goroutine .
死锁意味着所有 goroutine 都被阻塞。这不是这里的情况。
尝试从没有人(当前或曾经)准备发送的 channel 接收不是错误。如果是事实,那是完全正常的。这是 channel 的用例之一:它充当同步工具,您可以发送/接收,并且操作将阻塞,直到另一端也准备好。
在某些情况下,甚至在整个应用程序生命周期中阻塞的 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()
函数不会等待其他 goroutines 结束,它们可能在调用延迟函数时仍然处于事件状态,因此它们可能会或可能不会包含在剩余的 goroutines 计数中。如果你会使用例如sync.WaitGroup
等他们结束,那么他们肯定不会被包括在内。见 Prevent the main() function from terminating before goroutines finish in Golang例如。
关于go - 为什么没有接收器被阻塞的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59750056/