golang之recover時(shí)顯示調(diào)用棧信息

package main

import (
    "fmt"
    "os"
    "runtime"
    "sync"
    "time"
)

func main() {
    defer fmt.Println("defer main") // will this be called when panic?
    var user = os.Getenv("USER_")

    wg := sync.WaitGroup{}
    wg.Add(1)
    go func(wgPtr *sync.WaitGroup) {
        defer func() {
            fmt.Println("go defer")
            wgPtr.Done()
        }()
        defer func() {
            fmt.Println("defer here")
        }()

        defer func() {
            fmt.Println("defer caller")
            if x := recover(); x != nil {
                fmt.Println("recover success.")
                buf := make([]byte, 1<<16)
                runtime.Stack(buf, true)
                fmt.Println("buf", string(buf))
            }
        }()

        if user == "" {
            panic("should set user env.")
        }
        fmt.Println("after panic")
    }(&wg)
    wg.Wait()
    time.Sleep(1 * time.Second)
    fmt.Printf("get result %v\r\n", user)
}

輸出結(jié)果:

dev@dev-VirtualBox test $ go run test_panic_recover.go 
defer caller
recover success.
buf goroutine 6 [running]:
main.main.func1.3()
        /home/dev/test/test_panic_recover.go:31 +0x154
panic(0x4a2ce0, 0x4de010)
        /usr/local/go/src/runtime/panic.go:969 +0x166
main.main.func1(0xc000014070, 0x0, 0xc000014110)
        /home/dev/test/test_panic_recover.go:37 +0x129
created by main.main
        /home/dev/test/test_panic_recover.go:17 +0x13b

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc000014118)
        /usr/local/go/src/runtime/sema.go:56 +0x42
sync.(*WaitGroup).Wait(0xc000014110)
        /usr/local/go/src/sync/waitgroup.go:130 +0x64
main.main()
        /home/dev/test/test_panic_recover.go:41 +0x149

defer here
go defer
get result 
defer main

其中調(diào)用棧第一行的信息 /home/dev/test/test_panic_recover.go:31,其實(shí)就是runtime.Stack(buf, true)的位置,以后的信息就是panic的發(fā)生地方和調(diào)用地方等等。

如果recover代碼不是和panic在一個(gè)協(xié)程里,那么發(fā)生panic時(shí)就無法觸發(fā)recover了。如下例子:

package main

import (
    "fmt"
    "os"
    "sync"
    "time"
)

func main() {
    defer fmt.Println("defer main") // will this be called when panic?
    var user = os.Getenv("USER_")
    defer func() {
        fmt.Println("defer caller")
        if x := recover(); x != nil {
            fmt.Println("recover success.")
        }
    }()

    wg := sync.WaitGroup{}
    wg.Add(1)
    go func(wgPtr *sync.WaitGroup) {
        defer func() {
            fmt.Println("go defer")
            wgPtr.Done()
        }()
        defer func() {
            fmt.Println("defer here")
        }()

        if user == "" {
            panic("should set user env.")
        }
        fmt.Println("after panic")
    }(&wg)
    wg.Wait()
    time.Sleep(1 * time.Second)
    fmt.Printf("get result %v\r\n", user)
}

輸出結(jié)果:

dev@dev-VirtualBox test $ go run test_panic_recover.go 
defer here
go defer
panic: should set user env.

goroutine 6 [running]:
main.main.func2(0x0, 0x0, 0xc000014100)
    /home/dev/test/test_panic_recover.go:32 +0x10a
created by main.main
    /home/dev/test/test_panic_recover.go:22 +0x157
exit status 2

panic發(fā)生在子協(xié)程,recover在主協(xié)程,不在同一個(gè)協(xié)程里,整個(gè)程序就panic了,沒有輸出“recover success”就停止了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容