visit()
の機能をサブフォルダに入れないように変更して、同時にサブフォルダごとに新しいゴルーチンを起動して、並行処理を行うことができます。
これを行うには、エントリがディレクトリの場合はvisit()
関数から特殊なfilepath.SkipDir
エラーを返します。 がvisit()
の中にあるのが、ゴルーチンが処理しなければならないサブフォルダであるかどうかを確認することを忘れないでください。これはvisit()
にも渡されるので、このチェックを行わないと初期フォルダに対して無期限にゴルーチンを起動します。
また、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%が1つのサブフォルダにあり、そのゴルーチンが大部分の時間を費やします。
fmt.Printf()
コールはシリアル化されるため、処理が遅くなることにも注意してください。私はこれが単なる例であると仮定し、現実にはある種の処理/統計をメモリ内で行うでしょう。 visit()
関数からアクセスされる変数への同時アクセスを保護することも忘れないでください。
サブフォルダの数が多いことを心配しないでください。これは正常で、Goランタイムは数十万のゴルーチンにも対応できます。
また、パフォーマンスのボトルネックはストレージ/ハードディスクのスピードになる可能性が高いため、ご希望のパフォーマンスが得られない可能性があります。特定のポイント(ハードディスクの上限)の後、パフォーマンスを向上させることはできません。
また、各サブフォルダの新しいゴルーチンを起動することは最適ではない可能性があります。フォルダを歩いているゴルーチンの数を制限すると、パフォーマンスが向上する場合があります。そのために、チェックアウトして、労働者のプールを使用します。https://
Is this an idiomatic worker thread pool in Go?
各ファイルのゴルーチンを作成すると、私はあなたが労働者がディレクトリのみ、リンクを処理するためにゴルーチンの作成をお勧めします、すべてであなたを助けにはなりませんblog.golang.org/pipelines、https://gobyexample.com/worker-pools –