それぞれ2 GBの250以上のファイルがあるフォルダがあります。これらのファイルで文字列/パターンを検索し、その結果をoutput
ファイルに出力する必要があります。次のコマンドを実行できることはわかっていますが、遅すぎます。
grep mypattern * > output
スピードアップしたい。 Javaのプログラマーである私は、マルチスレッド化を使用してプロセスを高速化できることを知っています。 「マルチスレッドモード」でgrep
を起動し、出力を単一のoutput
ファイルに書き込む方法にこだわっています。
これには2つの簡単な解決策があります。基本的には、xargs
またはparallel
を使用します。
xargsアプローチ:
次のように、xargs
をfind
とともに使用できます。
find . -type f -print0 | xargs -0 -P number_of_processes grep mypattern > output
number_of_processes
を、起動するプロセスの最大数に置き換えます。ただし、パフォーマンスがI/Oに制限されている場合に、これが重大なパフォーマンスを保証するわけではありません。その場合、I/Oを待機するために失われた時間を補うために、より多くのプロセスを開始しようとする場合があります。
また、findを含めると、ファイルパターンだけでなく、変更時間などのより高度なオプションを指定できます。
Stéphaneのコメントで説明されているように、このアプローチで発生する可能性のある問題の1つは、ファイルが少ない場合、xargs
はそれらに対して十分な数のプロセスを開始できない可能性があります。 1つの解決策は、xargs
の-n
オプションを使用して、一度にパイプから取得する必要がある引数の数を指定することです。 -n1
を設定すると、xargs
が各ファイルごとに新しいプロセスを開始するように強制されます。ファイルが非常に大きく(この質問の場合のように)、ファイルの数が比較的少ない場合、これは望ましい動作である可能性があります。ただし、ファイル自体が小さい場合、新しいプロセスを開始するオーバーヘッドによって並列処理の利点が損なわれる可能性があります。その場合、-n
の値が大きいほど優れています。したがって、-n
オプションは、ファイルのサイズと数に応じて微調整される場合があります。
並列アプローチ:
それを行う別の方法は、Ole Tange GNU Parallel tool parallel
、(available here )を使用することです。これにより、並列処理と複数のホストに分散することもできます(たとえば、ディレクトリが共有されている場合に便利です)パラレルを使用する最も簡単な構文は次のとおりです。
find . -type f | parallel -j+1 grep mypattern
ここで、オプション-j+1
は、マシンのコア数を超えて1つのプロセスを開始するように並列に指示します(これは、I/Oが制限されたタスクに役立つ可能性があります。
Parallelには、各プロセスからの出力の順序を実際に保持し、連続した出力を生成するというxargs
よりも優れている点もあります。たとえば、xargs
の場合、プロセス1がp1L1
という行を生成し、プロセス2が行p2L1
を生成し、プロセス1が別の行p1L2
を生成する場合、出力は次のようになります。 :
p1L1
p2L1
p1L2
一方、parallel
の場合、出力は次のようになります。
p1L1
p1L2
p2L1
これは通常、xargs
出力よりも便利です。
CPU単位でgrepを高速化するには、少なくとも2つの方法があります。
正規表現ではなく固定文字列を検索する場合は、-F
フラグを指定します。
パターンがASCIIのみの場合は、UTF-8の代わりに8ビットロケールを使用します。 LC_ALL=C grep ...
。
ただし、ハードドライブがボトルネックになっている場合は、これらは役に立ちません。その場合、おそらく並列化も役に立たないでしょう。
問題がI/Oバウンドでない場合は、マルチコア処理用に最適化されたツールを使用できます。
Sift( http://sift-tool.org 、免責事項:私はこのツールの作成者です)またはシルバーサーチャー( https:// github.com/ggreer/the_silver_searcher )。
単純な文字列検索ではなく正規表現パターンを使用する場合、シルバーサーチャーのファイルサイズ制限は2GBです。