面试题答案
一键面试设计思路
- Context 创建与传递:在主文件处理任务开始时,创建一个顶层的
context.Context
,通常使用context.Background()
作为根上下文。然后将这个上下文传递给每个子任务,确保所有子任务共享相同的上下文环境,以便在需要时能够统一取消或超时控制。 - 子任务管理:使用
sync.WaitGroup
来等待所有子任务完成。每个子任务在启动时调用wg.Add(1)
,完成时调用wg.Done()
。 - 错误处理:每个子任务在遇到错误时,将错误信息通过通道传递给主任务。主任务通过监听这些通道,一旦收到错误,立即取消上下文,通知所有子任务停止,并记录错误信息以便定位问题。
- 资源清理:在子任务内部,确保在任务结束时(无论是否发生错误),正确关闭文件、释放数据库连接等资源,避免资源泄漏。
关键代码片段
package main
import (
"context"
"fmt"
"sync"
)
// 模拟文件读取任务
func fileRead(ctx context.Context, resultChan chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
select {
case <-ctx.Done():
return
default:
// 模拟文件读取操作
resultChan <- "file content"
}
}
// 模拟文件解析任务
func fileParse(ctx context.Context, inputChan <-chan string, resultChan chan<- string, wg *sync.WaitGroup) {
defer wg.Done()
select {
case <-ctx.Done():
return
case input := <-inputChan:
// 模拟文件解析操作
resultChan <- "parsed " + input
}
}
// 模拟文件存储任务
func fileStore(ctx context.Context, inputChan <-chan string, wg *sync.WaitGroup) {
defer wg.Done()
select {
case <-ctx.Done():
return
case input := <-inputChan:
// 模拟文件存储操作
fmt.Println("Stored:", input)
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
readResultChan := make(chan string)
parseResultChan := make(chan string)
// 启动文件读取任务
wg.Add(1)
go fileRead(ctx, readResultChan, &wg)
// 启动文件解析任务
wg.Add(1)
go fileParse(ctx, readResultChan, parseResultChan, &wg)
// 启动文件存储任务
wg.Add(1)
go fileStore(ctx, parseResultChan, &wg)
// 等待所有任务完成
go func() {
wg.Wait()
close(readResultChan)
close(parseResultChan)
}()
// 错误处理示例
// 假设文件读取任务发生错误,通过通道传递错误信息
errorChan := make(chan error)
go func() {
// 模拟文件读取错误
errorChan <- fmt.Errorf("file read error")
}()
select {
case err := <-errorChan:
fmt.Println("Error:", err)
cancel() // 取消上下文,终止所有子任务
}
// 等待所有任务真正结束
wg.Wait()
}
上述代码以Go语言为例,展示了如何在高并发文件处理系统中使用Context管理任务生命周期和错误处理。通过上下文传递、WaitGroup等待以及通道传递错误信息,实现了高效的任务管理和错误定位。