主线程中启动A协程,A协程中启动B协程,B协程中启动C协程,现A协程出现Panic,B和C正常。
context解决方式func A(ctx context.Context) {
ctx, cancel := context.WithCancel(ctx)
defer func() {
if err := recover(); err != nil {
log.Println("recover from panic:", err)
cancel()
}
}()
log.Println("A")
go B(ctx)
time.Sleep(10 * time.Second)
panic("err")
}
func B(ctx context.Context) {
go C(ctx)
// task
for {
select {
case <-ctx.Done():
log.Printf("b quit ctx.Done(): %v n", ctx.Err())
return
default:
}
log.Println("b")
time.Sleep(1 * time.Second)
}
}
func C(ctx context.Context) {
for {
select {
case <-ctx.Done():
log.Printf("c quit ctx.Done(): %v n", ctx.Err())
return
default:
}
log.Println("c")
time.Sleep(1 * time.Second)
}
}
channel解决方式
func A() {
signalCh := make(chan struct{})
wg := sync.WaitGroup{}
defer func() {
if err := recover(); err != nil {
log.Println(err)
close(signalCh)
wg.Wait()
}
}()
go B(&wg, signalCh)
time.Sleep(2 * time.Second)
panic("A")
}
func B(wg *sync.WaitGroup, ch <-chan struct{}) {
wg.Add(1)
defer func() {
wg.Done()
}()
log.Println("B start")
go C(wg, ch)
for {
select {
case <-ch:
log.Println("exit B")
return
default:
}
log.Println("B")
time.Sleep(time.Second)
}
}
func C(wg *sync.WaitGroup, ch <-chan struct{}) {
wg.Add(1)
defer func() {
wg.Done()
}()
log.Println("C start")
for {
select {
case <-ch:
log.Println("exit C")
return
default:
}
log.Println("C")
time.Sleep(time.Second)
}
}



