实现思路
- 使用
sync.WaitGroup
来等待所有子 goroutine
完成。
- 在每个子
goroutine
中使用 defer
配合 recover
来捕获 panic
。
- 将捕获到的
panic
信息通过 channel
传递给主 goroutine
进行处理。
代码示例
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup, panicCh chan interface{}) {
defer func() {
if r := recover(); r != nil {
panicCh <- fmt.Sprintf("goroutine %d panicked: %v", id, r)
}
wg.Done()
}()
// 模拟可能触发panic的操作
if id == 2 {
panic("simulated panic")
}
fmt.Printf("goroutine %d is working\n", id)
}
func main() {
var wg sync.WaitGroup
panicCh := make(chan interface{}, 10)
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg, panicCh)
}
go func() {
wg.Wait()
close(panicCh)
}()
for msg := range panicCh {
fmt.Println("Caught panic:", msg)
}
fmt.Println("All goroutines completed, program continues.")
}
优缺点分析
优点
- 性能:通过
defer
和 recover
在子 goroutine
内部捕获 panic
,减少了程序崩溃的风险,保证了整体性能不受单个 goroutine
崩溃的影响。
- 资源管理:使用
sync.WaitGroup
和 channel
进行同步和通信,资源管理清晰,每个 goroutine
的生命周期都能得到有效控制。未触发 panic
的 goroutine
可以继续工作,不会因为其他 goroutine
的问题而被终止,资源得以充分利用。
缺点
- 性能:
defer
和 recover
本身会带来一定的性能开销,尤其是在大量 goroutine
同时运行且频繁触发 panic
的情况下,这种开销可能会比较明显。
- 资源管理:使用
channel
传递 panic
信息,如果 channel
缓冲区设置不合理,可能会导致 goroutine
阻塞,进而影响程序的正常运行。同时,sync.WaitGroup
和 channel
的使用增加了代码的复杂性,对资源管理和调试带来一定挑战。