在 GOLANG 中尽可能快地递归遍历所有文件夹中的所有文件
Loop through all files in all folders recursively as fast as possible in GOLANG
我遇到了一个问题,即使在论坛上花了一天时间,我仍然无法完全理解和解决。
所以在这里,我创建了一个循环遍历所有文件夹及其子文件夹的函数,它有 2 个子函数:
- 对于找到的每个文件,列出文件的名称。
- 对于找到的每个文件夹,重新启动相同的父函数以再次查找子文件和文件夹。
为了简单起见,宏以递归方式列出了树中的所有文件。但我的目标是尽可能快地完成,所以我每次遇到新文件夹时 运行 一个新的 goroutine。
问题:
我的问题是,当树结构太大(文件夹和子文件夹中的文件夹太多......)时,脚本会生成太多线程,因此会给我一个错误。所以我增加了这个限制,但突然间它不再需要 :/
所以我的问题是,如何制作适合我的代码的辅助系统(带池大小)?
怎么看都看不出来,比如生成新的goroutines到一定的限度,清空缓冲区的时间。
源代码:
https://github.com/LaM0uette/FilesDIR/tree/V0.5
主要内容:
package main
import (
"FilesDIR/globals"
"FilesDIR/task"
"fmt"
"log"
"runtime/debug"
"sync"
"time"
)
func main() {
timeStart := time.Now()
debug.SetMaxThreads(5 * 1000)
var wg sync.WaitGroup
// task.DrawStart()
/*
err := task.LoopDir(globals.SrcPath)
if err != nil {
log.Print(err.Error())
}
*/
err := task.LoopDirsFiles(globals.SrcPath, &wg) // globals.SrcPath = My path with ~2000000 files ( this is a serveur of my entreprise)
if err != nil {
log.Print(err.Error())
}
wg.Wait()
fmt.Println("FINI: Nb Fichiers: ", task.Id)
timeEnd := time.Since(timeStart)
fmt.Println(timeEnd)
}
任务:
package task
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
var Id = 0
// LoopDir TODO: Code à supprimer / Code to delete
func LoopDir(path string) error {
var wg sync.WaitGroup
countDir := 0
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
wg.Add(1)
countDir++
go func() {
err := loopFiles(path, &wg)
if err != nil {
log.Println(err.Error())
}
}()
}
return nil
})
if err != nil {
return err
}
wg.Wait()
fmt.Println("Finished", countDir, Id)
return nil
}
// loopFiles TODO: Code à supprimer / Code to delete
func loopFiles(path string, wg *sync.WaitGroup) error {
files, err := ioutil.ReadDir(path)
if err != nil {
wg.Done()
return err
}
for _, file := range files {
if !file.IsDir() {
go fmt.Println(file.Name())
Id++
}
}
wg.Done()
return nil
}
func LoopDirsFiles(path string, wg *sync.WaitGroup) error {
wg.Add(1)
defer wg.Done()
files, err := ioutil.ReadDir(path)
if err != nil {
return err
}
for _, file := range files {
if !file.IsDir() && !strings.Contains(file.Name(), "~") {
fmt.Println(file.Name(), Id)
Id++
} else if file.IsDir() {
go func() {
err = LoopDirsFiles(filepath.Join(path, file.Name()), wg)
if err != nil {
log.Print(err)
}
}()
time.Sleep(20 * time.Millisecond)
}
}
return nil
}
如果您不想使用任何外部包,您可以创建一个单独的工作程序来处理文件,然后启动任意数量的工作程序。之后,在你的主线程中递归地进入树,并将工作发送给工人。如果任何工人“有时间”,它会从工作通道中挑选以下工作并处理它。
var (
wg *sync.WaitGroup
jobs chan string = make(chan string)
)
func loopFilesWorker() error {
for path := range jobs {
files, err := ioutil.ReadDir(path)
if err != nil {
wg.Done()
return err
}
for _, file := range files {
if !file.IsDir() {
fmt.Println(file.Name())
}
}
wg.Done()
}
return nil
}
func LoopDirsFiles(path string) error {
files, err := ioutil.ReadDir(path)
if err != nil {
return err
}
//Add this path as a job to the workers
//You must call it in a go routine, since if every worker is busy, then you have to wait for the channel to be free.
go func() {
wg.Add(1)
jobs <- path
}()
for _, file := range files {
if file.IsDir() {
//Recursively go further in the tree
LoopDirsFiles(filepath.Join(path, file.Name()))
}
}
return nil
}
func main() {
//Start as many workers you want, now 10 workers
for w := 1; w <= 10; w++ {
go loopFilesWorker()
}
//Start the recursion
LoopDirsFiles(globals.SrcPath)
wg.Wait()
}
我遇到了一个问题,即使在论坛上花了一天时间,我仍然无法完全理解和解决。
所以在这里,我创建了一个循环遍历所有文件夹及其子文件夹的函数,它有 2 个子函数: - 对于找到的每个文件,列出文件的名称。 - 对于找到的每个文件夹,重新启动相同的父函数以再次查找子文件和文件夹。
为了简单起见,宏以递归方式列出了树中的所有文件。但我的目标是尽可能快地完成,所以我每次遇到新文件夹时 运行 一个新的 goroutine。
问题:
我的问题是,当树结构太大(文件夹和子文件夹中的文件夹太多......)时,脚本会生成太多线程,因此会给我一个错误。所以我增加了这个限制,但突然间它不再需要 :/
所以我的问题是,如何制作适合我的代码的辅助系统(带池大小)? 怎么看都看不出来,比如生成新的goroutines到一定的限度,清空缓冲区的时间。
源代码:
https://github.com/LaM0uette/FilesDIR/tree/V0.5
主要内容:
package main
import (
"FilesDIR/globals"
"FilesDIR/task"
"fmt"
"log"
"runtime/debug"
"sync"
"time"
)
func main() {
timeStart := time.Now()
debug.SetMaxThreads(5 * 1000)
var wg sync.WaitGroup
// task.DrawStart()
/*
err := task.LoopDir(globals.SrcPath)
if err != nil {
log.Print(err.Error())
}
*/
err := task.LoopDirsFiles(globals.SrcPath, &wg) // globals.SrcPath = My path with ~2000000 files ( this is a serveur of my entreprise)
if err != nil {
log.Print(err.Error())
}
wg.Wait()
fmt.Println("FINI: Nb Fichiers: ", task.Id)
timeEnd := time.Since(timeStart)
fmt.Println(timeEnd)
}
任务:
package task
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
var Id = 0
// LoopDir TODO: Code à supprimer / Code to delete
func LoopDir(path string) error {
var wg sync.WaitGroup
countDir := 0
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
wg.Add(1)
countDir++
go func() {
err := loopFiles(path, &wg)
if err != nil {
log.Println(err.Error())
}
}()
}
return nil
})
if err != nil {
return err
}
wg.Wait()
fmt.Println("Finished", countDir, Id)
return nil
}
// loopFiles TODO: Code à supprimer / Code to delete
func loopFiles(path string, wg *sync.WaitGroup) error {
files, err := ioutil.ReadDir(path)
if err != nil {
wg.Done()
return err
}
for _, file := range files {
if !file.IsDir() {
go fmt.Println(file.Name())
Id++
}
}
wg.Done()
return nil
}
func LoopDirsFiles(path string, wg *sync.WaitGroup) error {
wg.Add(1)
defer wg.Done()
files, err := ioutil.ReadDir(path)
if err != nil {
return err
}
for _, file := range files {
if !file.IsDir() && !strings.Contains(file.Name(), "~") {
fmt.Println(file.Name(), Id)
Id++
} else if file.IsDir() {
go func() {
err = LoopDirsFiles(filepath.Join(path, file.Name()), wg)
if err != nil {
log.Print(err)
}
}()
time.Sleep(20 * time.Millisecond)
}
}
return nil
}
如果您不想使用任何外部包,您可以创建一个单独的工作程序来处理文件,然后启动任意数量的工作程序。之后,在你的主线程中递归地进入树,并将工作发送给工人。如果任何工人“有时间”,它会从工作通道中挑选以下工作并处理它。
var (
wg *sync.WaitGroup
jobs chan string = make(chan string)
)
func loopFilesWorker() error {
for path := range jobs {
files, err := ioutil.ReadDir(path)
if err != nil {
wg.Done()
return err
}
for _, file := range files {
if !file.IsDir() {
fmt.Println(file.Name())
}
}
wg.Done()
}
return nil
}
func LoopDirsFiles(path string) error {
files, err := ioutil.ReadDir(path)
if err != nil {
return err
}
//Add this path as a job to the workers
//You must call it in a go routine, since if every worker is busy, then you have to wait for the channel to be free.
go func() {
wg.Add(1)
jobs <- path
}()
for _, file := range files {
if file.IsDir() {
//Recursively go further in the tree
LoopDirsFiles(filepath.Join(path, file.Name()))
}
}
return nil
}
func main() {
//Start as many workers you want, now 10 workers
for w := 1; w <= 10; w++ {
go loopFilesWorker()
}
//Start the recursion
LoopDirsFiles(globals.SrcPath)
wg.Wait()
}