本文次要钻研一下gost的GoSafely

GoSafely

gost/runtime/goroutine.go

func GoSafely(wg *sync.WaitGroup, ignoreRecover bool, handler func(), catchFunc func(r interface{})) {    if wg != nil {        wg.Add(1)    }    go func() {        defer func() {            //......        }()        handler()    }()}
GoSafely接管WaitGroup、ignoreRecover、handler、catchFunc参数,其大抵的模板是,首先对WaitGroup进行add(1),而后一步执行带defer的handler

defer

gost/runtime/goroutine.go

        defer func() {            if r := recover(); r != nil {                if !ignoreRecover {                    fmt.Fprintf(os.Stderr, "%s goroutine panic: %v\n%s\n",                        time.Now(), r, string(debug.Stack()))                }                if catchFunc != nil {                    //......                }            }            if wg != nil {                wg.Done()            }        }()
GoSafely的defer先执行recover(),而后依据ignoreRecover判断是否打印err,最初解决WaitGroup,与一般recover不同的是多了一个catchFunc解决

catchFunc

gost/runtime/goroutine.go

                if catchFunc != nil {                    if wg != nil {                        wg.Add(1)                    }                    go func() {                        defer func() {                            if p := recover(); p != nil {                                if !ignoreRecover {                                    fmt.Fprintf(os.Stderr, "recover goroutine panic:%v\n%s\n",                                        p, string(debug.Stack()))                                }                            }                            if wg != nil {                                wg.Done()                            }                        }()                        catchFunc(r)                    }()                }
catchFunc算是一个mini版的GoSafely,先执行wg.Add(1),再异步执行func,异步func外头先注册defer,解决recover及wg,而后执行catchFunc

实例

gost/runtime/goroutine_test.go

func TestGoSafe(t *testing.T) {    times := int32(1)    var wg sync.WaitGroup    GoSafely(&wg,        false,        func() {            panic("hello")        },        func(r interface{}) {            atomic.AddInt32(&times, 1)        },    )    wg.Wait()    assert.True(t, atomic.LoadInt32(&times) == 2)    GoSafely(nil,        false,        func() {            panic("hello")        },        func(r interface{}) {            atomic.AddInt32(&times, 1)        },    )    time.Sleep(1e9)    assert.True(t, atomic.LoadInt32(&times) == 3)}
这里模仿了一下handler产生panic,一个有WaitGroup,一个没有WaitGroup的场景

小结

gost提供了GoSafely办法,它接管WaitGroup、ignoreRecover、handler、catchFunc参数,其大抵的模板是,首先对WaitGroup进行add(1),而后一步执行带defer的handler。catchFunc算是一个mini版的GoSafely,先执行wg.Add(1),再异步执行func,异步func外头先注册defer,解决recover及wg,而后执行catchFunc。

doc

  • gost