MST

星途 面试题库

面试题:Go语言recover使用限制在并发场景下的表现

在Go语言的并发编程中,我们经常使用goroutine。假设在一个goroutine中发生了panic,尝试在主goroutine中使用recover来捕获该panic,请问这样做会面临哪些问题?如何正确地在并发场景下处理panic并进行恢复操作?
33.3万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

面临的问题

  1. 作用域限制recover 只能在 defer 函数中生效,且仅能捕获当前 goroutine 中的 panic。在主 goroutine 中使用 recover 无法捕获其他 goroutine 中发生的 panic,因为每个 goroutine 都有自己独立的调用栈,主 goroutine 的调用栈与其他 goroutine 的调用栈相互隔离。

正确处理方式

  1. 使用通道
    • 在子 goroutine 中,当 panic 发生时,通过 recover 捕获 panic,然后将相关信息通过通道发送给主 goroutine。
    • 主 goroutine 从通道接收这些信息并进行处理。
    package main
    
    import (
        "fmt"
    )
    
    func main() {
        errorCh := make(chan interface{})
        go func() {
            defer func() {
                if err := recover(); err != nil {
                    errorCh <- err
                }
            }()
            // 模拟可能发生 panic 的操作
            panic("子 goroutine 发生 panic")
        }()
    
        if err := <-errorCh; err != nil {
            fmt.Println("捕获到 panic:", err)
        }
    }
    
  2. 使用 sync.WaitGroup 结合通道
    • 如果需要等待多个 goroutine 完成,可以结合 sync.WaitGroup
    • 每个子 goroutine 完成任务或者发生 panic 时,通过通道通知主 goroutine,并调用 WaitGroup.Done()
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main() {
        var wg sync.WaitGroup
        errorCh := make(chan interface{})
    
        for i := 0; i < 3; i++ {
            wg.Add(1)
            go func(id int) {
                defer func() {
                    if err := recover(); err != nil {
                        errorCh <- fmt.Sprintf("goroutine %d 发生 panic: %v", id, err)
                    }
                    wg.Done()
                }()
                // 模拟可能发生 panic 的操作
                if id == 1 {
                    panic("特定 goroutine 发生 panic")
                }
                fmt.Printf("goroutine %d 正常运行\n", id)
            }(i)
        }
    
        go func() {
            wg.Wait()
            close(errorCh)
        }()
    
        for err := range errorCh {
            fmt.Println("捕获到 panic:", err)
        }
    }