MST

星途 面试题库

面试题:Go语言中panic和recover在并发场景下的应用与陷阱

在一个包含多个goroutine的并发程序中,某个goroutine触发了panic,如何保证整个程序能够优雅地处理这个panic,避免程序崩溃?同时说明在这种并发场景下使用recover可能会遇到哪些陷阱,以及如何避免。请结合代码示例详细阐述。
48.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

保证程序优雅处理panic避免崩溃的方法

在Go语言中,使用deferrecover机制可以捕获并处理panic,防止程序崩溃。在并发场景下,需要在每个可能触发panicgoroutine中使用deferrecover

以下是一个示例代码:

package main

import (
    "fmt"
)

func worker(id int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Goroutine %d caught panic: %v\n", id, r)
        }
    }()

    // 模拟可能触发panic的操作
    if id == 2 {
        panic("simulated panic")
    }
    fmt.Printf("Goroutine %d is working\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }

    // 防止main函数退出
    select {}
}

在上述代码中,每个worker goroutine都使用了deferrecoverdefer函数在worker函数结束时执行,recover用于捕获panic。如果goroutine触发了panicrecover会捕获到并进行相应处理,避免程序崩溃。

并发场景下使用recover的陷阱及避免方法

  1. 陷阱:recover只能在defer函数中生效 如果不在defer函数中调用recover,它将返回nil,无法捕获panic。例如:
package main

import (
    "fmt"
)

func main() {
    if r := recover(); r != nil {
        fmt.Printf("Caught panic: %v\n", r)
    }
    panic("test panic")
}

上述代码中recover不在defer函数中,所以无法捕获panic,程序依然会崩溃。

  1. 陷阱:无法跨goroutine捕获panic recover只能捕获当前goroutine中的panic,无法捕获其他goroutinepanic。例如:
package main

import (
    "fmt"
)

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Caught panic: %v\n", r)
        }
    }()

    go func() {
        panic("test panic in goroutine")
    }()

    // 防止main函数退出
    select {}
}

上述代码中,main函数中的recover无法捕获到新goroutine中的panic,程序依然会崩溃。

  1. 避免方法
    • 确保recoverdefer函数中调用,以便在函数结束时捕获panic
    • 在每个可能触发panicgoroutine内部使用deferrecover,而不是在调用goroutine的外部尝试捕获panic。这样可以确保每个goroutine都能独立处理自身的panic,避免程序因某个goroutinepanic而崩溃。