背景
在微信群一位同學(xué)拋出的一段代碼, 各位看官猜想一下程序的執(zhí)行結(jié)果
// 程序1
func main() {
fmt.Println("running, not deadlock")
server, err := net.Listen("tcp", "127.0.0.1:9001")
if err != nil {
fmt.Println(err)
}
waitQueue := make(chan int)
for {
connection, err := server.Accept()
if err != nil {
panic("server")
}
fmt.Printf("Received connection from %s.\n", connection.RemoteAddr())
waitQueue <- 1
}
}
我猜想大部分同學(xué)都會說是: fatal error: all goroutines are asleep - deadlock!. 因為waitQueue是個沒有緩沖的channel, waitQueue <- 1向里面send一個值, 理論上程序一運(yùn)行就會報deadlock的錯誤
如下面這個例子
// 程序1
func main() {
waitQueue := make(chan int)
for {
waitQueue <- 1
}
}
這個程序的結(jié)果毫無疑問是: fatal error: all goroutines are asleep - deadlock!
但是文章一開頭的這個程序, 同學(xué)們在自己機(jī)器上運(yùn)行一下, 我想99%的人應(yīng)該得到的是下面的結(jié)果: running, not deadlock
我甚至把程序?qū)懙母鼧O端些
// 程序3
func main() {
fmt.Println("running, not deadlock")
waitQueue := make(chan int)
waitQueue <- 1
return
server, err := net.Listen("tcp", "127.0.0.1:9001")
if err != nil {
fmt.Println(err)
}
for {
connection, err := server.Accept()
if err != nil {
panic("server")
}
fmt.Printf("Received connection from %s.\n", connection.RemoteAddr())
}
}
程序3和程序1不同的地方是: 我把整個channel放在了程序開始, 甚至直接return, 依然不會出現(xiàn)deadlock
是不是陷入了深深的懷疑之中?
我分別在macOS, linux, ubuntu上面驗證了1.10, 1.12.2, 1.12.5, 1.12.6都不會出現(xiàn)deadlock
于是我在golang的GitHub上提了這個issue, bcmills很快回復(fù)了為什么不會出現(xiàn)deadlock的提示. 他的大概意思是golang built-in deadlock detector 在某些情況下是被禁用, 如通過C庫進(jìn)行系統(tǒng)調(diào)用. deadlock detector觸發(fā)依賴于goroutine的調(diào)度和系統(tǒng)調(diào)用的具體實(shí)現(xiàn). deadlock detector是一個有用的工具, 但是不能完全替代集成測試和負(fù)載測試



具體討論內(nèi)容可以查看: https://github.com/golang/go/issues/33004
也不是說所有的環(huán)境下都不會出現(xiàn)deadlock, 至少在golang playground就出現(xiàn)了

具體在往深處我就沒有去追究built-in deadlock detector的實(shí)現(xiàn)了, 等后面再補(bǔ)充這個. 不過從這里也可以看出來, 我們不能還是要寫好單元測試, 集成測試等避免goroutine leaks出現(xiàn), 不能過分依賴與deadlock detector