在运行goroutine时,在新函数中运行和不在新函数中运行之间的区别是什么?

huangapple go评论143阅读模式
英文:

difference between in recover when run goroutine in new func or not

问题

这段代码涉及到defer和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

为什么看起来不同呢?如果有人能给我详细的解释,谢谢你。

英文:

It is about defer and recover, to catch runtime error.

version 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")
}

Version 2 (Only func b() changed) :

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

difference
run version 1:

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

and version 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

why it looks different?
thank you if someone can give me the detail message.

答案1

得分: 4

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

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

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

在你的第二个示例中,你调用了一个没有参数的函数,然后在该函数中发生了panic。由于goroutine中没有调用recover(),所以你看到了默认的panic处理程序。

defer/recover()只能捕获同一goroutine中的panic。

如果你在b的顶部添加defer/recover,你将能够捕获它并进行任何操作(例如:像你在#1中那样打印它)。

英文:

In version 1, your panic happens in the main goroutine because []string{}[2] must be resolved before the goroutine can be spawned.

All arguments to a function must be resolved before it gets dispatched, and goroutines are no different.

A goroutine works basically the same as any other function call except that after the stack is setup for the call, it executes in a separate context (thread).

in your second example, you are calling a function with no args and then in that function you are panicing. Since there is no call to recover() in the goroutine, you are seeing the default panic handler.

defer/recover() can only capture a panic within the same goroutine.

If you add a defer / recover to the top of b, you will be able to capture it and do whatever (ie: println it like you did in #1)

huangapple
  • 本文由 发表于 2016年3月17日 12:15:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/36051562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定