MST

星途 面试题库

面试题:Go并发程序复杂场景下的异常传播与处理策略

在一个多层嵌套调用且高度并发的Go程序中,不同层次的goroutine可能会产生不同类型的异常,有些异常需要向上层goroutine传播,有些则需要在本地处理并记录日志,同时要保证整个系统的稳定性和性能不受太大影响。请设计一个通用的异常捕获和处理框架,详细描述架构设计、关键数据结构和处理流程,并给出必要的代码片段。
11.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

架构设计

  1. 异常传播机制:通过返回值或者 channel 来传播异常。在 Go 中,通常函数返回 error 类型的值来表示异常情况,对于 goroutine 间通信,可以使用 channel 来传递异常。
  2. 本地处理与日志记录:每个 goroutine 内部有一个异常处理逻辑,当捕获到需要本地处理的异常时,记录日志并继续执行或者优雅地结束当前 goroutine。
  3. 稳定性与性能:为避免过多的异常处理开销影响性能,对于频繁出现的异常,可以采用异步日志记录等方式,减少对主线程的阻塞。同时,在异常传播过程中,尽量减少不必要的数据拷贝。

关键数据结构

  1. Error类型:Go 语言内置的 error 类型用于表示异常情况。可以自定义 error 类型,以便区分不同类型的异常。
type CustomError struct {
    ErrMsg string
}

func (ce CustomError) Error() string {
    return ce.ErrMsg
}
  1. 日志记录结构:可以使用标准库的 log 包或者第三方日志库如 zap。例如,使用 zap 时,定义一个全局的 logger。
var logger *zap.Logger

func init() {
    var err error
    logger, err = zap.NewProduction()
    if err != nil {
        panic(err)
    }
    defer logger.Sync()
}

处理流程

  1. 本地处理:每个 goroutine 在执行核心逻辑时,使用 deferrecover 来捕获未处理的 panic 异常,并进行本地处理。
func worker() {
    defer func() {
        if r := recover(); r != nil {
            logger.Error("Panic occurred", zap.Any("reason", r))
        }
    }()
    // 核心业务逻辑
    // 可能会触发异常的代码
}
  1. 异常传播:对于需要向上层传播的异常,通过函数返回值传递 error。上层调用者检查 error 并决定如何处理。
func subTask() error {
    // 执行任务
    if someCondition {
        return CustomError{"Sub task failed"}
    }
    return nil
}

func mainTask() error {
    err := subTask()
    if err != nil {
        // 可以选择继续向上传播
        return err
    }
    return nil
}

代码片段汇总

package main

import (
    "fmt"
    "go.uber.org/zap"
)

type CustomError struct {
    ErrMsg string
}

func (ce CustomError) Error() string {
    return ce.ErrMsg
}

var logger *zap.Logger

func init() {
    var err error
    logger, err = zap.NewProduction()
    if err != nil {
        panic(err)
    }
    defer logger.Sync()
}

func subTask() error {
    // 执行任务
    if someCondition {
        return CustomError{"Sub task failed"}
    }
    return nil
}

func mainTask() error {
    err := subTask()
    if err != nil {
        // 可以选择继续向上传播
        return err
    }
    return nil
}

func worker() {
    defer func() {
        if r := recover(); r != nil {
            logger.Error("Panic occurred", zap.Any("reason", r))
        }
    }()
    // 核心业务逻辑
    // 可能会触发异常的代码
}

通过上述架构设计、数据结构和处理流程,可以实现一个在多层嵌套调用且高度并发的 Go 程序中的通用异常捕获和处理框架。在实际应用中,还可以根据具体需求进一步优化和扩展,例如增加分布式追踪等功能。