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



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

版本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 (仅更改了函数 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 中,你的恐慌发生在主 goroutine 中,因为 []string{}[2] 必须在生成 goroutine 之前解决。

函数的所有参数都必须在被调度之前解析,goroutines 也不例外。

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

在第二个示例中,您正在调用一个没有 args 的函数,然后在该函数中您感到恐慌。 由于 goroutine 中没有调用 recover(),因此您会看到默认的 panic 处理程序。

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

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

最新更新