MST
星途 面试题库

面试题:Go中Goroutine与通道在复杂异步场景下的资源管理

假设有一个需要处理大量数据文件的任务,每个文件处理是一个独立的Goroutine。设计一个系统,使用通道来管理任务分发、结果收集以及避免资源泄露(如文件句柄未关闭等情况)。请描述设计思路,并给出关键部分的代码示例。
30.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 任务分发:创建一个任务通道,将待处理的文件路径放入该通道。每个Goroutine从这个通道中获取文件路径进行处理。
  2. 结果收集:创建一个结果通道,每个Goroutine处理完文件后将结果发送到这个通道。主程序从结果通道中收集所有任务的处理结果。
  3. 资源管理:在Goroutine内部,确保文件在使用完毕后正确关闭,防止文件句柄未关闭导致资源泄露。

关键代码示例

package main

import (
    "fmt"
    "os"
)

// FileTask 定义文件任务结构
type FileTask struct {
    Path string
}

// FileResult 定义文件处理结果结构
type FileResult struct {
    Path string
    Err  error
}

func processFile(task FileTask, resultChan chan<- FileResult) {
    file, err := os.Open(task.Path)
    if err != nil {
        resultChan <- FileResult{Path: task.Path, Err: err}
        return
    }
    defer file.Close()

    // 这里添加具体的文件处理逻辑

    resultChan <- FileResult{Path: task.Path, Err: nil}
}

func main() {
    taskChan := make(chan FileTask)
    resultChan := make(chan FileResult)

    // 启动若干Goroutine处理任务
    numWorkers := 5
    for i := 0; i < numWorkers; i++ {
        go func() {
            for task := range taskChan {
                processFile(task, resultChan)
            }
        }()
    }

    // 模拟添加任务
    tasks := []FileTask{
        {Path: "file1.txt"},
        {Path: "file2.txt"},
        {Path: "file3.txt"},
    }
    for _, task := range tasks {
        taskChan <- task
    }
    close(taskChan)

    // 收集结果
    results := make([]FileResult, 0, len(tasks))
    for i := 0; i < len(tasks); i++ {
        results = append(results, <-resultChan)
    }
    close(resultChan)

    // 处理结果
    for _, result := range results {
        if result.Err != nil {
            fmt.Printf("处理文件 %s 出错: %v\n", result.Path, result.Err)
        } else {
            fmt.Printf("文件 %s 处理成功\n", result.Path)
        }
    }
}

上述代码中:

  1. FileTask 结构体用于表示文件任务,包含文件路径。
  2. FileResult 结构体用于表示文件处理结果,包含文件路径和可能的错误。
  3. processFile 函数负责打开文件、处理文件并关闭文件,然后将结果发送到结果通道。
  4. main 函数中,创建了任务通道和结果通道,并启动多个Goroutine从任务通道获取任务进行处理。任务添加完毕后关闭任务通道,通过结果通道收集所有任务的处理结果并处理。