导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

golang fatal error: all goroutines are asleep - deadlock!

Posted on   蝈蝈俊  阅读(11787)  评论(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

编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
历史上的今天:
2013-02-17 Go语言中的数组(array)和数组切片(slice)
点击右上角即可分享
微信分享提示