LeM*_*sel 4 filesystems parallel-processing concurrency file-io go
我想获取目录中文件的文件信息(文件名和大小,以字节为单位).但是有很多子目录(~1000)和文件(~40 000).
实际上我的解决方案是使用filepath.Walk()来获取每个文件的文件信息.但这很长.
func visit(path string, f os.FileInfo, err error) error {
if f.Mode().IsRegular() {
fmt.Printf("Visited: %s File name: %s Size: %d bytes\n", path, f.Name(), f.Size())
}
return nil
}
func main() {
flag.Parse()
root := "C:/Users/HERNOUX-06523/go/src/boilerpipe" //flag.Arg(0)
filepath.Walk(root, visit)
}
Run Code Online (Sandbox Code Playgroud)
是否可以使用filepath.Walk()进行并行/并发处理?
您可以通过修改visit()函数以不进入子文件夹来进行并发处理,但为每个子文件夹启动一个新的goroutine.
为此,如果条目是目录,filepath.SkipDir则从visit()函数返回特殊错误.不要忘记检查path内部visit()是否是goroutine应该处理的子文件夹,因为它也被传递给visit(),并且没有这个检查你将无休止地为初始文件夹启动goroutines.
此外,您需要某种"计数器",表示有多少goroutine仍在后台工作,您可以使用sync.WaitGroup.
这是一个简单的实现:
var wg sync.WaitGroup
func walkDir(dir string) {
defer wg.Done()
visit := func(path string, f os.FileInfo, err error) error {
if f.IsDir() && path != dir {
wg.Add(1)
go walkDir(path)
return filepath.SkipDir
}
if f.Mode().IsRegular() {
fmt.Printf("Visited: %s File name: %s Size: %d bytes\n",
path, f.Name(), f.Size())
}
return nil
}
filepath.Walk(dir, visit)
}
func main() {
flag.Parse()
root := "folder/to/walk" //flag.Arg(0)
wg.Add(1)
walkDir(root)
wg.Wait()
}
Run Code Online (Sandbox Code Playgroud)
一些说明:
根据子文件夹中文件的"分布",这可能无法充分利用您的CPU /存储,就好像例如99%的所有文件都在一个子文件夹中一样,goroutine仍将花费大部分时间.
另请注意,fmt.Printf()呼叫是序列化的,因此也会减慢进程.我假设这只是一个例子,实际上你会在内存中进行某种处理/统计.不要忘记还保护对从visit()函数访问的变量的并发访问.
不要担心大量的子文件夹.这是正常的,Go运行时甚至可以处理数十万个goroutine.
另请注意,性能瓶颈很可能是您的存储/硬盘速度,因此您可能无法获得所需的性能.在某一点(您的硬盘限制)之后,您将无法提高性能.
同时为每个子文件夹启动一个新的goroutine可能不是最佳选择,可能是通过限制文件夹中的goroutine数量来获得更好的性能.为此,请检查并使用工作池:
| 归档时间: |
|
| 查看次数: |
1022 次 |
| 最近记录: |