序
本文次要钻研一下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(×, 1) }, ) wg.Wait() assert.True(t, atomic.LoadInt32(×) == 2) GoSafely(nil, false, func() { panic("hello") }, func(r interface{}) { atomic.AddInt32(×, 1) }, ) time.Sleep(1e9) assert.True(t, atomic.LoadInt32(×) == 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