导航

golang fatal error: all goroutines are asleep - deadlock!

Posted on 2015-02-17 11:26  蝈蝈俊  阅读(11781)  评论(1编辑  收藏  举报

channel默认上是阻塞的,也就是说,如果Channel满了,就阻塞写,如果Channel空了,就阻塞读。阻塞的含义就是一直等到轮到它为止。单有时候我们会收到 fatal error: all goroutines are asleep - deadlock!  异常,这是如何呢?

代码例子:

package main

import "fmt"

func main() {
    channel := make(chan string, 2)

    fmt.Println("1")
    channel <- "h1"
    fmt.Println("2")
    channel <- "w2"
    fmt.Println("3")
    channel <- "c3"    // 执行到这一步,直接报 error
    fmt.Println("...")
    msg1 := <-channel
    fmt.Println(msg1)
}

执行效果:

image

参考:

http://stackoverflow.com/questions/26927479/go-language-fatal-error-all-goroutines-are-asleep-deadlock

 

fatal error: all goroutines are asleep - deadlock!

出错信息的意思是:
在main goroutine线,期望从管道中获得一个数据,而这个数据必须是其他goroutine线放入管道的
但是其他goroutine线都已经执行完了(all goroutines are asleep),那么就永远不会有数据放入管道。
所以,main goroutine线在等一个永远不会来的数据,那整个程序就永远等下去了。
这显然是没有结果的,所以这个程序就说“算了吧,不坚持了,我自己自杀掉,报一个错给代码作者,我被deadlock了”

 

这里是系统自动在除了主协程之外的协程都关闭后,做的检查,继而报出的错误, 证明思路如下, 在100秒内, 我们看不到异常, 100秒后,系统报错。

package main

import (
    "fmt"
    "time"
)

func main() {
    channel := make(chan string, 2)

    go func() {
        fmt.Println("sleep 1")
        time.Sleep(100 * time.Second)
        fmt.Println("sleep 2")
    }()

    fmt.Println("1")
    channel <- "h1"
    fmt.Println("2")
    channel <- "w2"

    fmt.Println("3")
    channel <- "c3"

    fmt.Println("...")
    msg1 := <-channel
    fmt.Println(msg1)
}

100秒内执行效果截图:

image

100秒后执行效果截图:

image

 

如果避免上面异常抛出呢?这时候我们可以用 select来帮我们处理。

package main

import "fmt"

func main() {
    channel := make(chan string, 2)

    fmt.Println("1")
    channel <- "h1"
    fmt.Println("2")
    channel <- "w2"

    fmt.Println("3")
    select {

    case channel <- "c3":
        fmt.Println("ok")
    default:
        fmt.Println("channel is full !")
    }

    fmt.Println("...")
    msg1 := <-channel
    fmt.Println(msg1)
}

执行效果:

image

这时候,我们把第三个要写入的 chan 抛弃了。

 

上面的例子中是写的例子, 读的例子也一样,下面的异常是  ws := <-channel 这一行抛出的。

channel := make(chan string, 2)

fmt.Println("begin")
ws := <-channel
fmt.Println(ws)

image