面试题答案
一键面试设计思路
- 错误传递:
- 使用
context.Context
来传递取消信号和携带值,它可以贯穿整个 goroutine 树,当子 goroutine 发生错误时,可以通过 context 取消整个相关的 goroutine 链。 - 利用通道(channel)在不同 goroutine 之间传递错误信息。一个 goroutine 发生错误时,将错误发送到特定的通道,上层模块从该通道接收错误。
- 使用
- 恢复机制:
- 在 goroutine 内部使用
defer
和recover
来捕获未处理的 panic,避免整个程序崩溃。捕获到 panic 后,可以将其转换为错误信息并通过通道传递出去。
- 在 goroutine 内部使用
代码框架
package main
import (
"context"
"fmt"
)
// 模拟一个可能出错的模块
func module(ctx context.Context, errCh chan<- error) {
defer func() {
if r := recover(); r != nil {
err := fmt.Errorf("recovered from panic: %v", r)
errCh <- err
}
}()
// 模拟业务逻辑
select {
case <-ctx.Done():
return
default:
// 这里模拟一个可能发生的错误
if someCondition {
err := fmt.Errorf("module internal error")
errCh <- err
return
}
}
}
func main() {
errCh := make(chan error)
ctx, cancel := context.WithCancel(context.Background())
go module(ctx, errCh)
go func() {
// 这里可以添加其他 goroutine 的启动
// 等待错误发生或者所有 goroutine 完成
for i := 0; i < numGoroutines; i++ {
select {
case err := <-errCh:
fmt.Printf("Received error: %v\n", err)
cancel() // 取消所有相关的 goroutine
}
}
close(errCh)
}()
// 主 goroutine 可以做其他事情
//...
// 等待所有事情完成
select {}
}
在上述代码框架中:
module
函数模拟一个可能出错的模块,它使用defer
和recover
捕获 panic 并转换为错误。main
函数中启动了module
goroutine,并通过errCh
通道接收错误。当接收到错误时,通过cancel
函数取消所有相关的 goroutine。- 主 goroutine 可以在等待错误的同时做其他事情,并且通过一个无限的
select {}
等待所有任务完成。