您可以通過修改visit()
函數不進入子文件夾來執行併發處理,但爲每個子文件夾啓動一個新的goroutine。
爲此,如果條目是目錄,請從visit()
函數返回特殊的filepath.SkipDir
錯誤。不要忘記檢查visit()
裏面的path
是否應該處理子例程,因爲這也會傳遞給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()
}
一些注意事項:
根據子文件夾中的文件的「分配」,這可能不是完全利用CPU /存儲,彷彿例如所有文件的99%都在一個子文件夾中,那麼goroutine仍然佔用大部分時間。
另外請注意,fmt.Printf()
調用是序列化的,這樣也會減慢進程。我認爲這只是一個例子,實際上你會在內存中做一些處理/統計。不要忘記同時保護從visit()
函數訪問的變量。
不要擔心大量的子文件夾。這是正常的,Go運行時能夠處理數十萬個goroutine。
另請注意,最有可能的性能瓶頸將是你的存儲/硬盤速度,所以你可能無法獲得你想要的性能。在某個點(您的硬盤限制)之後,您將無法提高性能。
也爲每個子文件夾啓動一個新的goroutine可能不是最佳的,它可能是通過限制遍歷文件夾的goroutine的數量來獲得更好的性能。爲此,檢查和使用工作池:
Is this an idiomatic worker thread pool in Go?
創建爲每個文件的goroutine不會幫助你在所有的,我建議你創建一個工作夠程僅處理目錄,鏈接:https://開頭blog.golang.org/pipelines,https://gobyexample.com/worker-pools –