当前位置 博文首页 > golang panic及处理机制

    golang panic及处理机制

    作者:布叔喂丶 时间:2021-09-13 18:03

    目录
    • 一 panic机制
    • 二 实例   
      • 2.1 main用recover
      • 2.2 func用recover
      • 2.3 func用recover且开创goroutine
      • 2.4 goroutine中panic
      • 2.5 func1内嵌func2中panic且func2做处理
      • 2.6 func1内嵌func中panic且func1做处理

    一 panic机制

      panic会将这个异常不断向上抛出,直到有地方处理它,如果有处理,则不会再向上抛出。倘若没有处理,那么最终会导致main挂掉.

     golang虽然没有try catch机制,却有一种类似的recover机制,后续demo我们可以观测到它的用法和作用

    二 实例   

    2.1 main用recover

    func main() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("err:", err)
            }
        }()
        go test1()
        time.Sleep(time.Second * 3)
        panic(errors.New("stop test1"))
        log.Println("123")
        select {}
    }
    func test1() {
        for {
            tm := time.NewTicker(time.Second)
            select {
            case <-tm.C:
                log.Println("test1")
            }
        }
    }

    2.2 func用recover

    func main() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("err:", err)
            }
        }()
        go test1()
        time.Sleep(time.Second * 3)
        makeerr()
        log.Println("123")
        select {}
    }
     
    func test1() {
        for {
            tm := time.NewTicker(time.Second)
            select {
            case <-tm.C:
                log.Println("test1")
            }
        }
    }
    func makeerr() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("makeerr:", err)
            }
        }()
        panic(errors.New("stop"))
    }

    此时我们在func中用recover,那么挂掉的只是func,他不会抛到main中,所以main能继续运行,继而main开辟的go test1也能继续运行

    2.3 func用recover且开创goroutine

    func main() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("err:", err)
            }
        }()
     
        time.Sleep(time.Second * 3)
        makeerr()
        log.Println("123")
        select {}
    }
     
    func test1() {
        for {
            tm := time.NewTicker(time.Second)
            select {
            case <-tm.C:
                log.Println("test1")
            }
        }
    }
    func makeerr() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("makeerr err:", err)
            }
        }()
        go test1()
        panic(errors.New("stop test"))
    }

    我们发现,func虽然挂掉了,但是他开创的go没挂掉,因为即使是这个函数退出了,新开的协程是相当于基于main下的一个子程,只要main不退出,他依然会“存活”

    2.4 goroutine中panic

    func main() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("err:", err)
            }
        }()
        go test1()
        time.Sleep(time.Second * 3)
        log.Println("123")
        select {}
    }
    func test1() {
        log.Println("test1 start")
        panic(errors.New("stop test1"))
        log.Println("test1 end")
    }

    协程中如果没recover,那么error就会抛向main,main就会挂掉,从而没有执行到后面的log打印。

    ---> 这种情况,main中做defer recover是没用的

    2.5 func1内嵌func2中panic且func2做处理

    func main() {
        test1()
        time.Sleep(time.Second * 3)
        log.Println("123")
    }
    func test1() {
        log.Println("test1 start")
        test2()
        log.Println("test1 end")
    }
    func test2() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("test2 err:", err)
            }
        }()
        log.Println("test2 start")
        panic(errors.New("stop test2"))
        log.Println("test2 end")
    }

    2.6 func1内嵌func中panic且func1做处理

    func main() {
        test1()
        time.Sleep(time.Second * 3)
        log.Println("123")
    }
    func test1() {
        defer func() {
            if err := recover(); err != nil {
                log.Println("test? err:", err)
            }
        }()
        log.Println("test1 start")
        test2()
        log.Println("test1 end")
    }
    func test2() {
        log.Println("test2 start")
        panic(errors.New("stop test2"))
        log.Println("test2 end")
    }

    func2异常,执行终止,向调用者func1抛出进而本身退出,func1得到异常,执行终止,本身退出时recover进行处理,从而保活了main

    jsjbwy