MST

星途 面试题库

面试题:Go Context错误处理在并发与资源管理中的深度应用

假设你正在开发一个高并发的文件处理系统,每个文件处理任务需要创建多个并发的子任务(如文件读取、解析、存储等),并且要使用Context来管理这些任务的生命周期和错误处理。在这个场景下,如何设计一个高效的Context传递与错误处理方案,以避免资源泄漏、确保任务的有序终止,并且能够在发生错误时快速定位问题根源?请详细说明你的设计思路和关键代码片段。
14.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. Context 创建与传递:在主文件处理任务开始时,创建一个顶层的 context.Context,通常使用 context.Background() 作为根上下文。然后将这个上下文传递给每个子任务,确保所有子任务共享相同的上下文环境,以便在需要时能够统一取消或超时控制。
  2. 子任务管理:使用 sync.WaitGroup 来等待所有子任务完成。每个子任务在启动时调用 wg.Add(1),完成时调用 wg.Done()
  3. 错误处理:每个子任务在遇到错误时,将错误信息通过通道传递给主任务。主任务通过监听这些通道,一旦收到错误,立即取消上下文,通知所有子任务停止,并记录错误信息以便定位问题。
  4. 资源清理:在子任务内部,确保在任务结束时(无论是否发生错误),正确关闭文件、释放数据库连接等资源,避免资源泄漏。

关键代码片段

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等待以及通道传递错误信息,实现了高效的任务管理和错误定位。