面试题答案
一键面试设计思路
- 任务分发:创建一个任务通道,将待处理的文件路径放入该通道。每个Goroutine从这个通道中获取文件路径进行处理。
- 结果收集:创建一个结果通道,每个Goroutine处理完文件后将结果发送到这个通道。主程序从结果通道中收集所有任务的处理结果。
- 资源管理:在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)
}
}
}
上述代码中:
FileTask
结构体用于表示文件任务,包含文件路径。FileResult
结构体用于表示文件处理结果,包含文件路径和可能的错误。processFile
函数负责打开文件、处理文件并关闭文件,然后将结果发送到结果通道。- 在
main
函数中,创建了任务通道和结果通道,并启动多个Goroutine从任务通道获取任务进行处理。任务添加完毕后关闭任务通道,通过结果通道收集所有任务的处理结果并处理。