MST

星途 面试题库

面试题:Go基于channel生产者消费者模式下的异常处理与健壮性设计

在一个Go语言编写的基于channel的生产者消费者系统中,生产者可能会遇到外部资源(如数据库连接、文件读取)获取失败等异常情况,消费者在处理数据时也可能出现各种运行时错误。请设计一套全面的异常处理机制,确保系统在出现异常时不会崩溃,并且能尽可能优雅地恢复或提供清晰的错误信息。描述你的设计思路,并给出关键代码片段。
47.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 生产者异常处理:在获取外部资源时使用try-catch类似的if err != nil语句捕获错误。如果获取资源失败,向一个专门的错误channel发送错误信息,同时停止生产数据。
  2. 消费者异常处理:在处理数据时使用recover机制来捕获运行时错误(如空指针引用等)。捕获到错误后,向错误channel发送错误信息,同时可以选择暂停处理当前数据,等待生产者修复问题后继续处理。
  3. 全局错误处理:设置一个单独的协程监听错误channel,接收到错误后进行统一处理,如记录日志、通知运维人员、尝试重启相关资源等。

关键代码片段

package main

import (
    "fmt"
    "log"
)

// 假设这是一个模拟获取外部资源的函数
func getExternalResource() (interface{}, error) {
    // 模拟失败情况
    return nil, fmt.Errorf("failed to get external resource")
}

func producer(dataCh chan<- interface{}, errCh chan<- error) {
    resource, err := getExternalResource()
    if err != nil {
        errCh <- err
        close(dataCh)
        return
    }
    // 假设这里从资源中读取数据并发送到dataCh
    // 简单模拟发送一些数据
    for i := 0; i < 5; i++ {
        dataCh <- fmt.Sprintf("data from resource: %d", i)
    }
    close(dataCh)
}

func consumer(dataCh <-chan interface{}, errCh chan<- error) {
    for data := range dataCh {
        defer func() {
            if r := recover(); r != nil {
                err, ok := r.(error)
                if!ok {
                    err = fmt.Errorf("unknown panic: %v", r)
                }
                errCh <- err
            }
        }()
        // 模拟处理数据时可能出现的错误
        if _, ok := data.(string);!ok {
            panic(fmt.Errorf("unexpected data type"))
        }
        fmt.Printf("Consumed: %v\n", data)
    }
}

func errorHandler(errCh <-chan error) {
    for err := range errCh {
        log.Printf("Error: %v\n", err)
        // 这里可以添加更多处理逻辑,如通知运维等
    }
}

你可以在main函数中调用这些函数:

func main() {
    dataCh := make(chan interface{})
    errCh := make(chan error)

    go producer(dataCh, errCh)
    go consumer(dataCh, errCh)
    go errorHandler(errCh)

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