面试题答案
一键面试设计思路
- 使用context.Context传递取消信号:通过context.Context可以在goroutine树中传递取消信号,当底层goroutine发生异常时,可以取消上层的goroutine,避免资源浪费和不可控状态。
- 使用error类型传递异常信息:在函数调用过程中,通过返回error类型来传递异常信息,这样可以保证异常信息在调用栈中安全传递。
- 在顶层goroutine统一处理异常:最外层的goroutine负责捕获所有的异常,并进行统一处理。
关键实现要点
- 创建和传递context.Context:在启动最外层goroutine时创建一个context.Context,并在调用下层goroutine时传递该context。
- 返回error并检查:每个函数在执行可能出错的操作时,返回error,并在调用处检查该error。
- 恢复异常:使用
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)
}
}
}
在上述伪代码中:
lowLevelFunction
函数模拟底层操作,可能返回异常。middleLevelFunction
函数调用lowLevelFunction
,并传递异常。topLevelFunction
函数启动middleLevelFunction
所在的goroutine,并在goroutine返回异常时,取消所有相关goroutine,并统一处理异常。