2017-05-30 3 views
3

ディレクトリ内のファイルのファイル情報(ファイル名&バイト)を取得したいとします。しかし、サブディレクトリ(〜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) 
} 

filepath.Walk()を使用して並列/並行処理を行うことはできますか?

+0

各ファイルのゴルーチンを作成すると、私はあなたが労働者がディレクトリのみ、リンクを処理するためにゴルーチンの作成をお勧めします、すべてであなたを助けにはなりませんblog.golang.org/pipelines、https://gobyexample.com/worker-pools –

答えて

6

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?

+0

私はよく生産者 - 消費者のパターンをマスターしません。 'producer()'はサブフォルダをウォーキングに送り、 'consumer()'はmycaseでそれを表示します。フォルダを歩くゴルーチンの数は、「消費者」の数によって制限されます。 – LeMoussel

+0

@LeMousselはい、そのようなものです。私の例では、 'go'で新しいgoroutineを起動するのではなく、' walkDir() 'を実行することによって)' walk'へのパスを取り出すためにコンシューマーが監視するチャンネルに 'path'を送ります。 – icza