本文主要研究一下gost的GoSafelygit
gost/runtime/goroutine.gogithub
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
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處理
gost/runtime/goroutine.goatom
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.godebug
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。code