MST
星途 面试题库

面试题:Go函数重构与并发性能优化

假设你有一个Go函数用来处理大量图片的压缩任务,函数接收一个图片文件路径的切片作为输入,对每张图片进行压缩并保存到指定目录。如下是简化版代码: ```go func CompressImages(imagePaths []string, outputDir string) error { for _, path := range imagePaths { img, err := ioutil.ReadFile(path) if err != nil { return err } compressedImg, err := CompressImage(img) if err != nil { return err } outputPath := filepath.Join(outputDir, filepath.Base(path)) err = ioutil.WriteFile(outputPath, compressedImg, 0644) if err != nil { return err } } return nil } func CompressImage(img []byte) ([]byte, error) { // 这里是实际的图片压缩逻辑,省略具体实现 return img, nil } ``` 请对 `CompressImages` 函数进行重构,利用Go的并发特性优化性能,同时要处理好并发过程中的错误处理、资源竞争等问题,确保程序的正确性和稳定性。
27.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "fmt"
    "io/ioutil"
    "path/filepath"
    "sync"
)

func CompressImages(imagePaths []string, outputDir string) error {
    var wg sync.WaitGroup
    var mu sync.Mutex
    errChan := make(chan error, len(imagePaths))

    for _, path := range imagePaths {
        wg.Add(1)
        go func(p string) {
            defer wg.Done()
            img, err := ioutil.ReadFile(p)
            if err != nil {
                errChan <- err
                return
            }
            compressedImg, err := CompressImage(img)
            if err != nil {
                errChan <- err
                return
            }
            outputPath := filepath.Join(outputDir, filepath.Base(p))
            mu.Lock()
            err = ioutil.WriteFile(outputPath, compressedImg, 0644)
            mu.Unlock()
            if err != nil {
                errChan <- err
                return
            }
        }(path)
    }

    go func() {
        wg.Wait()
        close(errChan)
    }()

    for err := range errChan {
        if err != nil {
            return err
        }
    }

    return nil
}

func CompressImage(img []byte) ([]byte, error) {
    // 这里是实际的图片压缩逻辑,省略具体实现
    return img, nil
}
  1. 并发处理:通过go关键字启动多个协程并行处理每张图片的压缩任务。
  2. 错误处理:使用errChan通道来收集每个协程中的错误,如果有错误发生,主函数可以及时返回错误。
  3. 资源竞争:使用sync.Mutex互斥锁来保护对文件写入操作,避免多个协程同时写入文件导致的数据竞争问题。
  4. 等待所有任务完成:使用sync.WaitGroup来等待所有协程完成任务后再关闭errChan通道,确保主函数不会提前返回。