序
本文主要研究一下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
有疑问加站长微信联系(非本文作者)