在新func中运行goroutine时恢复之间的差异

时间:2016-03-17 04:15:32

标签: go deferred goroutine recover

关于延迟和恢复,以捕获运行时错误。

版本1:

func a() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
        }
    }()
    b()
}

func b() {
    go fmt.Println([]string{}[2])
}

func main() {
    a()
    time.Sleep(1 * time.Second)
    fmt.Println("end")
}

版本2(仅更改了func b()):

func b() {
    go func() {
        fmt.Println([]string{}[2])
    }()
}

差 运行版本1:

> go run /tmp/version1.go 
runtime error: index out of range
end

和版本2:

> go run /tmp/t.go 
panic: runtime error: index out of range

goroutine 5 [running]:
main.b.func1()
    /tmp/t.go:19 +0x109
created by main.b
    /tmp/t.go:20 +0x2b

goroutine 1 [sleep]:
time.Sleep(0x3b9aca00)
    /usr/local/go/src/runtime/time.go:59 +0xf9
main.main()
    /tmp/t.go:25 +0x29
exit status 2

为什么它看起来不一样? 谢谢,如果有人能给我详细的信息。

1 个答案:

答案 0 :(得分:4)

在版本1中,您的恐慌发生在主goroutine中,因为必须在生成goroutine之前解析[] string {} [2]。

函数的所有参数必须在调度之前解析,而goroutines也没有区别。

goroutine的工作方式与其他任何函数调用基本相同,只是在为调用设置堆栈之后,它在单独的上下文(线程)中执行。

在你的第二个例子中,你正在调用一个没有args的函数,然后在那个函数中你正在惊慌失措。由于在goroutine中没有调用recover(),因此您将看到默认的恐慌处理程序。

defer / recover()只能捕获同一个goroutine中的恐慌。

如果你将延迟/恢复添加到b的顶部,你将能够捕获它并做任何事情(即:像你在#1中那样打印)