MST

星途 面试题库

面试题:Go中跨goroutine边界的异常传播与恢复机制设计

假设有一个复杂的Go程序,包含多个层次的goroutine调用。一个底层goroutine发生异常后,需要将异常信息安全且高效地传播到最外层调用的goroutine进行统一处理,同时要确保中间层的goroutine不会因异常而处于不可控状态。请设计一套合理的异常传播与恢复机制,并说明设计思路和关键实现要点,可使用伪代码辅助说明。
42.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 使用context.Context传递取消信号:通过context.Context可以在goroutine树中传递取消信号,当底层goroutine发生异常时,可以取消上层的goroutine,避免资源浪费和不可控状态。
  2. 使用error类型传递异常信息:在函数调用过程中,通过返回error类型来传递异常信息,这样可以保证异常信息在调用栈中安全传递。
  3. 在顶层goroutine统一处理异常:最外层的goroutine负责捕获所有的异常,并进行统一处理。

关键实现要点

  1. 创建和传递context.Context:在启动最外层goroutine时创建一个context.Context,并在调用下层goroutine时传递该context。
  2. 返回error并检查:每个函数在执行可能出错的操作时,返回error,并在调用处检查该error。
  3. 恢复异常:使用recover函数在goroutine中捕获未处理的异常,避免程序崩溃。

伪代码示例

package main

import (
    "context"
    "fmt"
)

// 底层函数,可能发生异常
func lowLevelFunction(ctx context.Context) error {
    select {
    case <-ctx.Done():
        return ctx.Err()
    default:
        // 模拟异常情况
        if someCondition {
            return fmt.Errorf("low level error")
        }
        return nil
    }
}

// 中间层函数,调用底层函数
func middleLevelFunction(ctx context.Context) error {
    err := lowLevelFunction(ctx)
    if err != nil {
        return err
    }
    // 中间层其他操作
    return nil
}

// 最外层函数,启动goroutine并处理异常
func topLevelFunction() {
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    var err error
    go func() {
        err = middleLevelFunction(ctx)
        if err != nil {
            cancel() // 发生异常,取消所有goroutine
        }
    }()

    // 等待goroutine完成
    select {
    case <-ctx.Done():
        if err != nil {
            fmt.Println("Caught error:", err)
        }
    }
}

在上述伪代码中:

  1. lowLevelFunction函数模拟底层操作,可能返回异常。
  2. middleLevelFunction函数调用lowLevelFunction,并传递异常。
  3. topLevelFunction函数启动middleLevelFunction所在的goroutine,并在goroutine返回异常时,取消所有相关goroutine,并统一处理异常。