go - 为什么在全局范围内声明通道会产生死锁问题
问题描述
在 3 个代码片段中,一个在本地范围内声明了通道的代码片段有效,其他代码片段给出了死锁问题,此处先前回答的 SO 问题之一说尽量避免在全局范围内声明通道。我查看了官方文档,但没有找到任何解释。
尽管我没有阻止通道发送和接收,但为什么全局范围通道会出错?为什么我在这里遇到死锁问题?
在范围和初始化方面与 except
make(chan int)
有何不同?var myChan chan int
任何人都可以解释和建议更好的文章/文档/链接/pdfs 以在 Go 中有效地使用通道(并实现并发)吗?
(为简洁起见,片段中省略了导入和“主包”)
// 1. channel declared in global scope
var c chan int
func main(){
go send()
fmt.Println(<-c)
}
func send(){
c <- 42
}
//output: fatal error: all goroutines are asleep - deadlock!
// 2. channel declared in global scope + sending channel to goroutine
var c chan int
func main(){
go send(c)
fmt.Println(<-c)
}
func send(c chan int){
c <- 42
}
//output: fatal error: all goroutines are asleep - deadlock!
// 3. using channel as local scope and sharing it with goroutine
func main(){
c := make(chan int)
go send(c)
fmt.Println(<-c)
}
func send(c chan int){
c <- 42
}
解决方案
因为通过声明一个 uninitialized var c chan int
,c
它的类型的值为零,在 a 的情况下chan
是nil
。
如果您实际运行您的代码,错误消息会显示此信息。nil
两个 goroutine 都在chan上发送/接收:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive (nil chan)]:
main.main()
/tmp/sandbox288806111/prog.go:11 +0x5c
goroutine 18 [chan send (nil chan)]:
main.send()
/tmp/sandbox288806111/prog.go:15 +0x39
created by main.main
/tmp/sandbox288806111/prog.go:10 +0x39
相反,make
您正在显式初始化变量c
,然后不是nil
。
这与全局范围本身无关。事实上,如果你正确地初始化变量,例如var c chan int = make(chan int)
,即使在全局范围内,程序也不会死锁。
附加读物:通道公理 (Dave Cheney)
如果通道为 nil,则发送者和接收者之间没有相互引用;他们都被阻塞在独立的频道上等待并且永远不会解除阻塞。
推荐阅读
- corda - Corda 单元测试:及格列表
> - java - 为什么我们需要在 C++ 中检查空指针,而在 Java 中不需要?
- neo4j - Neo4J (Cypher):我想创建 x 个节点,这些节点都与单个父节点双向连接,我该怎么做?
- php - 文本文件内容到带有子级别的数组
- html - 使用 flex 网格系统引导此标头的最佳方法是什么?
- c++ - 使用 GCC 4.8.5 构建的应用程序中对 cxx11 函数的未定义引用
- apache-spark-sql - 为什么 Spark 总是向 HDFS 写入相同数量的文件?
- count - sparql 选择多个计数返回不同的结果
- r - 如何屏蔽给定选定条目的向量
- css - 使用 CSS3 变量不工作来设置背景图像 url?