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


8

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

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

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

現在、GNUパラレルを使用してパラレルgrepを実行しようとしています。

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

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

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

何が悪いのですか?

回答:


9

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

あなたのボトルネックは、GNU Parallelにある可能性が最も高い--pipeです。非常に効率的ではありません。--pipepartただし、次のとおりです。ここでは、CPUコアあたり1 GB /秒のオーダーで取得できます。

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

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

例:

parallel --pipepart -a bigfile --block 100M grep somepattern

1
ありがとう。--pipe非効率的である理由はありますか?つまり、それはある種の根本的な問題、または実装固有のものです。
Denis Bazhenov、2015

2
はい:GNU Parallelはperlで記述されており--pipe、1バイトごとに1つのプロセスを実行する必要があります。このプロセスでは、各バイトで少し処理を行う必要があります。--pipepartほとんどのバイトは、中央処理で見たことがないされています。彼らは、生成されたジョブによって処理されています。ボトルネックとなっているのはかなり数行なので--pipe、Cコンパイラをパスに持っている人のために実行される部分を書き直すC / C ++コーダーを歓迎します。
Ole

2

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

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

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

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

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


1
確かに、それは私の場合です。非常にCPUを消費するJavaプロセスがgrepの代わりに使用されます。質問を少し簡略化しました。それでも、大量のCPUを並行して使用しても、Javaプロセスに多くの作業は提供されません。
Denis Bazhenov、2015

1

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

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


1
を使用する場合、解凍がボトルネックになるとは思われませんparallel。それは確かに最初のケース(並列なし)ですが、2番目のケース(並列あり)ではボトルネックが並列側にあることに同意します。これは、によって測定されたように、スループットが大幅に低下しているという観察に基づいていますpv。ボトルネックが圧縮解除されている場合、パイプラインに追加したスループットは変化しません。スループットの定義は非常に直感的だと思います–スループットを最も制限するものです。
Denis Bazhenov、2015

1
grepが非常に高速で、parallelパイプに書き込むよりも速く終了する可能性があります。この場合、ほとんどのgrepプロセスparallelは、ブロックを複数のパイプに多重化するために24時間体制で作業している間、追加の取得を待機します(これは、追加のIO操作であり、バッファーがいっぱいの場合、解凍をブロックすることさえあります)。また、--blockパラメーターで遊んでみましたか?デフォルトでは1M、1つのgrepが1Mデータを取得するまで、残りはほぼ確実に完了しています。したがって、これを並列化しても意味がないという事実に戻ります。
オリオン2015

1
うん、私は大小のブロックサイズでこのオプションを試しました。-N/ -Lオプションの値も異なります。デフォルトのオプションは、私が経験したローカルの最適値に非常に近いようです:)
Denis Bazhenov

1
pv(を使用してtime)使用して、使用せずにタイミングを試してください。これにより、pv速度が低下しているかどうかを確認できます。もしそうなら、parallelパイプにデータをコピーすることは間違いなく追加のオーバーヘッドです。とにかくgrep、特にパターンがバックトラックの少ない単純な文字列である場合は、ほぼリアルタイムであると確信しています。さらに、出力parallelをインターリーブして混乱させgrepます。
オリオン2015

1
pvそれ自体で問題が発生しないことをクロスチェックします。アドバイスをありがとうございます。
Denis Bazhenov、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.