面试题答案
一键面试设计思路
- 生产者异常处理:在获取外部资源时使用
try-catch
类似的if err != nil
语句捕获错误。如果获取资源失败,向一个专门的错误channel
发送错误信息,同时停止生产数据。 - 消费者异常处理:在处理数据时使用
recover
机制来捕获运行时错误(如空指针引用等)。捕获到错误后,向错误channel
发送错误信息,同时可以选择暂停处理当前数据,等待生产者修复问题后继续处理。 - 全局错误处理:设置一个单独的协程监听错误
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 {}
}