代码实现
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
)
func processFile(filePath string, wg *sync.WaitGroup) {
defer wg.Done()
data, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Printf("读取文件 %s 出错: %v\n", filePath, err)
return
}
upperContent := strings.Map(func(r rune) rune {
if r >= 'a' && r <= 'z' {
return r - 32
}
return r
}, string(data))
newFilePath := strings.Replace(filePath, ".", "_upper.", 1)
err = ioutil.WriteFile(newFilePath, []byte(upperContent), 0644)
if err != nil {
fmt.Printf("写入文件 %s 出错: %v\n", newFilePath, err)
}
}
func main() {
directory := "/your/directory/path"
var wg sync.WaitGroup
var filePaths []string
err := filepath.Walk(directory, func(filePath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if!info.IsDir() {
filePaths = append(filePaths, filePath)
}
return nil
})
if err != nil {
fmt.Printf("遍历目录出错: %v\n", err)
return
}
for _, filePath := range filePaths {
wg.Add(1)
go processFile(filePath, &wg)
}
wg.Wait()
}
可能出现的问题及解决方法
- 文件竞争:
- 问题描述:多个 goroutine 同时读写文件可能导致数据不一致。
- 解决方法:在写入文件时,使用
ioutil.WriteFile
函数,它会以独占方式创建或截断文件,避免竞争。如果需要更细粒度控制,可以使用 sync.Mutex
对文件操作部分进行加锁,但在高并发场景下可能会影响性能。
- 资源耗尽:
- 问题描述:创建过多的 goroutine 可能耗尽系统资源(如文件描述符等)。
- 解决方法:可以使用
sync.WaitGroup
结合有限的 goroutine 池来控制并发数。例如,创建一个有缓冲的 channel 作为 goroutine 池,当 channel 满时,新的任务需要等待直到有空闲的 goroutine。
性能优化思路
- 限制并发数:如上述解决资源耗尽问题时,合理设置 goroutine 池大小,避免过多的并发导致系统资源耗尽和上下文切换开销。
- 批量操作:可以批量读取和写入文件,减少系统调用次数。例如,一次读取多个文件的内容到内存中,处理后再批量写入新文件。但要注意内存的使用,避免内存溢出。
- 优化字符串处理:使用
strings.Map
进行字符转换已经是比较高效的方式,但如果有特殊需求,也可以考虑其他优化方式,如使用 bytes.Buffer
进行字符串拼接以减少内存分配次数。
- 预分配内存:在处理文件内容时,根据文件大致大小预分配内存空间,减少动态内存分配的开销。