我们学习通道channel的时候,偶尔会在测试的时候遇到 all goroutines are asleep
这样的panic错误,但是这个是怎么造成的呢。本文首先会介绍产生这个的原因,然后会结合具体案例进行详细分析。
错误原因
这个错误其实已经写的比较明白了,所有的 协程(goroutines)都处于休眠(阻塞)状态
。当所有协程都处于阻塞状态的时候,那所有的协程都等不来解锁的那一天了,出现死锁,所以golang调度直接把这个给kill掉了。
简单来说出现这样的原因是主线程在阻塞,但是其他协程由于各种原因也阻塞了。
下面分享几个学习中遇到的案例
案例详解(持续更新)
案例一
代码如下:
package main
import (
"fmt"
"time"
)
func service1(ch chan string) {
fmt.Println("BEEFORE")
ch <- "from service1"
fmt.Println("AFTER")
}
func main() {
var ch chan string
go service1(nil)
fmt.Printf("sleep at :%d\n",time.Now().Unix())
time.Sleep(time.Second * 2)
fmt.Printf("weak at :%d\n",time.Now().Unix())
for {
select {
case str := <-ch:
fmt.Println(str)
}
}
}
执行结果如下:
➜ Q22 go run .
sleep at :1562689190
BEEFORE
weak at :1562689192
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
/Users/gaoke/work/go/mine/Q22/main.go:23 +0x19a
goroutine 5 [chan send (nil chan)]:
main.service1(0x0)
/Users/gaoke/work/go/mine/Q22/main.go:10 +0x7b
created by main.main
/Users/gaoke/work/go/mine/Q22/main.go:17 +0x42
exit status 2
出现了我们期待的 all goroutines are asleep
。可见所有线程都阻塞了,但是我们这个代码是想结果协程传来的字符串啊,为什么会阻塞呢。
这里就涉及了 协程的知识了,因为我们只是简单声明了下chan
,ch
还是nil.
当
channel
是nil
的时候,无论是传入数据还是取出数据,都会永久的block。
回到我们代码,因为ch
是nil
,所以在service1中这个协程被永久的阻塞了,当我们在select的时候又被阻塞了。这也就造成了所有协程阻塞,出现死锁,代码panic。
有疑问加站长微信联系(非本文作者)