web-dev-qa-db-ja.com

GNU並列を効果的に使用する方法

圧縮されたテキストファイルですべての一致を検索するとします。

$ gzcat file.txt.gz | pv --rate -i 5 | grep some-pattern

pv --rateここではパイプスループットの測定に使用されます。私のマシンでは、約420Mb/s(解凍後)です。

現在、GNU parallelを使用して並列grepを実行しようとしています。

$ gzcat documents.json.gz | pv --rate -i 5 | parallel --pipe -j4 --round-robin grep some-pattern

現在、スループットは約260Mb/sに低下しています。そして、より興味をそそるparallelプロセス自体は、多くのCPUを使用しています。 grepプロセスより多い(ただしgzcat未満)。

EDIT 1:さまざまなブロックサイズ(--block)と、-N/-Lオプションのさまざまな値を試しました。現時点では何も助けになりません。

私は何が間違っているのですか?

8
Denis Bazhenov

GNU Parallelの--pipeを使用して270MB/sを取得できることに本当に驚いています。私のテストは通常​​約100MB/sで最大になります。

あなたのボトルネックはGNU Parallel:--pipeはあまり効率的ではありません。ただし、--pipepartは次のようになります:1 GB /秒のオーダーで取得できます。 CPUコアごと。

残念ながら、--pipepartの使用にはいくつかの制限があります。

  • ファイルはシーク可能である必要があります(つまり、パイプがない)
  • --recstart /-recendを使用してレコードの先頭を見つけることができる必要があります(つまり、圧縮ファイルはありません)。
  • 行番号は不明です(したがって、4行のレコードを持つことはできません)。

例:

parallel --pipepart -a bigfile --block 100M grep somepattern
9
Ole Tange

grepは非常に効果的です-それを並行して実行する意味はありません。あなたのコマンドでは、解凍だけがより多くのCPUを必要としますが、これを並列化することはできません。

入力を並列で分割するには、grepで一致する行を取得するよりも多くのCPUが必要です。

Grepの代わりに、各行にはるかに多くのCPUが必要なものを使用したい場合は、状況が変化します。並列処理の方が意味があります。

この操作を高速化したい場合は、ボトルネックがどこにあるかを調べてください。おそらく、解凍(他の解凍ツールまたはより優れたCPUの使用に役立ちます)または-ディスクからの読み取り(他の解凍ツールまたはより優れたディスクシステムの使用に役立ちます)です。

私の経験から(たとえば、lzma(-2など)を使用してファイルを圧縮/解凍する方が良い場合があります)、gzipよりも圧縮率が高いため、ディスクから読み取る必要のあるデータがはるかに少なく、速度は同等です。

2
undefine

ここでのボトルネックは減圧です。解凍が内部的に並列化されていない場合、自分でそれを達成することはできません。そのようなジョブが複数ある場合は、もちろんそれらを並行して起動しますが、パイプライン自体を並列化するのは困難です。 1つのストリームを並列ストリームに分割することは、ほとんど価値がなく、同期とマージで非常に苦痛になる可能性があります。複数のコアが実行中のすべてのタスクに役立つとは限らないことを受け入れる必要がある場合があります。

一般に、シェルでの並列化は、ほとんどの場合、独立したプロセスのレベルで行う必要があります。

1
orion