MST

星途 面试题库

面试题:Go的Goroutine异常处理与并发安全

假设你有多个Goroutine并发执行任务,一个Goroutine发生panic,如何确保其他Goroutine不受影响,并正确清理资源?请说明实现思路及关键代码片段。
26.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 实现思路
    • 在每个Goroutine中使用recover来捕获panic,这样可以避免panic导致整个程序崩溃。
    • 为了正确清理资源,可以使用defer语句。defer会在函数返回或panic发生时执行,因此可以在defer中编写资源清理代码。
    • 可以使用一个共享的状态变量(如sync.Mutex保护的布尔值)来标记某个Goroutine是否发生了panic,其他Goroutine可以根据这个状态决定是否继续执行或进行相应的处理。
  2. 关键代码片段
package main

import (
    "fmt"
    "sync"
)

var (
    panicOccurred bool
    mu            sync.Mutex
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    defer func() {
        if r := recover(); r != nil {
            mu.Lock()
            panicOccurred = true
            mu.Unlock()
            fmt.Printf("Goroutine %d caught panic: %v\n", id, r)
        }
    }()

    // 模拟任务
    if id == 2 {
        panic("Simulated panic in Goroutine 2")
    }
    fmt.Printf("Goroutine %d is working\n", id)
}

func main() {
    var wg sync.WaitGroup
    numWorkers := 3

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

    wg.Wait()

    if panicOccurred {
        fmt.Println("A panic occurred, but other Goroutines continued.")
    } else {
        fmt.Println("No panic occurred.")
    }
}

在上述代码中:

  • worker函数使用deferrecover来捕获可能的panic
  • panicOccurredmu用于记录和保护是否发生panic的状态。
  • main函数中,启动多个Goroutine并等待它们完成,然后根据panicOccurred的值输出相应的信息。这样可以确保即使某个Goroutine发生panic,其他Goroutine也能继续执行并正确清理资源。