MST

星途 面试题库

面试题:Go中recover在复杂并发场景下的应用

在一个包含多个goroutine的复杂并发程序中,其中某些goroutine可能会发生panic。请设计一个机制,使用recover来捕获这些panic,同时要保证其他正常运行的goroutine不受影响,并且能够将发生panic的goroutine的详细信息(如函数调用栈、传入的参数等)记录下来,以便于调试。要求给出完整的代码示例,并对关键部分进行详细注释。
21.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "fmt"
    "runtime"
    "sync"
)

// 定义一个结构体来记录panic的详细信息
type PanicInfo struct {
    FuncName string
    Args     []interface{}
    Stack    string
}

// 用于记录panic信息的全局变量
var panicInfos []PanicInfo
var mu sync.Mutex

// 捕获panic并记录信息的函数
func recoverAndLog() {
    if r := recover(); r != nil {
        var buf [4096]byte
        n := runtime.Stack(buf[:], false)
        stack := string(buf[:n])

        // 这里假设能获取到函数名和参数,实际情况可能需要更复杂逻辑
        funcName := "unknown"
        args := []interface{}{}

        panicInfo := PanicInfo{
            FuncName: funcName,
            Args:     args,
            Stack:    stack,
        }

        mu.Lock()
        panicInfos = append(panicInfos, panicInfo)
        mu.Unlock()
    }
}

// 模拟可能发生panic的goroutine
func worker(id int, wg *sync.WaitGroup) {
    defer func() {
        recoverAndLog()
        wg.Done()
    }()

    if id == 3 { // 假设id为3时发生panic
        panic("模拟panic")
    }
    fmt.Printf("Goroutine %d is running\n", id)
}

func main() {
    var wg sync.WaitGroup
    numGoroutines := 5

    for i := 0; i < numGoroutines; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()

    // 打印记录的panic信息
    mu.Lock()
    for _, info := range panicInfos {
        fmt.Printf("Function: %s\n", info.FuncName)
        fmt.Printf("Args: %v\n", info.Args)
        fmt.Printf("Stack: %s\n", info.Stack)
    }
    mu.Unlock()
}

关键部分注释

  1. PanicInfo结构体:用于存储发生panic的goroutine的函数名、传入参数和函数调用栈信息。
  2. recoverAndLog函数:使用recover捕获panic,获取调用栈信息,并将相关信息记录到panicInfos中。
  3. worker函数:模拟可能发生panic的goroutine,使用defer调用recoverAndLog来捕获panic,确保即使发生panic也能正确结束该goroutine,不影响其他goroutine。
  4. main函数:启动多个goroutine,并等待它们完成。最后打印记录的panic信息。sync.Mutex用于保证对panicInfos的并发安全访问。