パイプコマンドの並列実行


16

次のシナリオを検討してください。2つのプログラムAとBがあります。プログラムAは文字列の標準出力行に出力し、プログラムBは標準入力からの行を処理します。これらの2つのプログラムを使用する方法は、もちろん次のとおりです。

foo @ bar:〜$ A | B

今、私はこれが1つのコアのみを消費することに気付きました。したがって、私は疑問に思っています:

プログラムAとBは同じ計算リソースを共有していますか?その場合、AとBを同時に実行する方法はありますか?

私が気づいたもう1つのことは、AがBよりもはるかに高速に実行されることです。したがって、どういうわけかより多くのBプログラムを実行して、Aが出力する行を並行して処理できるかどうか疑問に思っています。

つまり、Aはその行を出力し、プログラムBのN個のインスタンスがあり、これらの行を(最初に読み取る人は誰でも)読み取り、処理してstdoutに出力します。

私の最後の質問は:

潜在的に発生する可能性のある競合状態やその他の矛盾を気にすることなく、いくつかのBプロセス間でAに出力をパイプする方法はありますか?


1
ながらA | B | Cによるパイプの性質のために、別々のプロセスのように平行であり、それはまだいくつかのケースでは線形であってもよい(BはAの出力を待たなければならない、CはBの出力を待たなければなりません)。それは彼らがどのような出力を生成するかに完全に依存します。複数の実行Bが大いに役立つケースは多くありません。並列wcの例はwc、分割が通常行をカウントするよりも多くのリソースを消費する可能性があるため、通常よりも遅い可能性があります。注意して使用してください。
frostschutz

回答:


14

問題split --filterは、出力が混同される可能性があるため、プロセス1から半分の行を取得し、その後プロセス2から半分の行を取得することです。

GNU Parallelは、混乱がないことを保証します。

だからあなたがやりたいと仮定します:

 A | B | C

しかし、そのBは非常に遅いため、これを並列化する必要があります。その後、次のことができます。

A | parallel --pipe B | C

GNU Parallelは、デフォルトで\ nおよび1 MBのブロックサイズで分割します。これは--recendおよび--blockで調整できます。

GNU Parallelの詳細については、http//www.gnu.org/s/parallel/をご覧ください。

GNU Parallelは次のコマンドでわずか10秒でインストールできます。

wget -O - pi.dk/3 | sh 

http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1の紹介ビデオを見る


1
私はインストール方法に強く反対しますが:-)、あなたのソリューションは私の問題のほとんどを解決するので+1。
LSerni

これは確かにいいです。使用するパラメーターについて何か提案はありますか?プログラムAは、毎分約5GBのデータを1TB以上出力することを知っています。プログラムBは、Aが出力するデータの5倍の速度でデータを処理し、このタスクのために5つのコアを自由に使用できます。
Jernej

現在、GNU Parallelは最大で約100 MB /秒を処理できるため、この制限に触れます。最適なサイズ--block-sizeは、RAMの量と、新しいを開始できる速度によって異なりますB。あなたの状況では、私はそれを使用--block 100Mして、それがどのように実行されるかを確認します。
オレ丹下

@lserniより良いインストール方法を思い付くことができます。これはほとんどのUNIXマシンで機能し、ユーザーからの同様の作業量が必要です。
オレ丹下

4
申し訳ありませんが、私は自分自身を明確にしませんでした。インストール方法-渡されるスクリプトsh-は素晴らしいです。問題は、それをshに渡すことにあります:サイトから実行可能コードをダウンロードして実行します。カスタムメイドのRPMまたはDEBは基本的に同じものであることに反対する可能性があり、コピーして貼り付けるページにコードを投稿しても、人々は盲目的に行うのでとにかく。
LSerni

13

を記述するとA | B、両方のプロセスがすでに並行し実行されます。1つのコアのみを使用していると思われる場合、CPUアフィニティ設定(おそらく、異なるアフィニティのプロセスを生成するツールがある)か、1つのプロセスではコア全体を保持するには不十分であり、コンピューティングを普及させたくない」。

1つのAで複数のBを実行splitするには、--filterオプションなどのツールが必要です。

A | split [OPTIONS] --filter="B"

ただし、Bジョブはすべて同じ速度で実行されるわけではないため、これは出力の行の順序を台無しにしがちです。これが問題になる場合は、B i番目の出力を中間ファイルにリダイレクトし、最後にを使用してつなぎ合わせる必要がありますcat。これにより、かなりのディスク容量が必要になる場合があります。

その他のオプションがあります(たとえば、Bの各インスタンスを単一の行バッファー出力に制限し、Bの「ラウンド」全体が終了するまで待機し、reduce to splitmapに相当するものを実行しcat、一時出力を一緒に実行できます)、さまざまなレベルの効率で。たとえば、今説明した「ラウンド」オプションは、B最も遅いインスタンスが終了するまで待機するため、Bの使用可能なバッファリングに大きく依存します。[m]buffer操作が何であるかに応じて、役立つ場合もあれば、そうでない場合もあります。

最初の1000個の数値を生成し、並行して行をカウントします。

seq 1 1000 | split -n r/10 -u --filter="wc -l"
100
100
100
100
100
100
100
100
100
100

行を「マーク」すると、最初の各行がプロセス#1に送信され、5行目がプロセス#5に送信されます。さらに、split2番目のプロセスを生成するのにかかる時間では、最初のプロセスが既にその割り当てに適した方法です。

seq 1 1000 | split -n r/10 -u --filter="sed -e 's/^/$RANDOM - /g'" | head -n 10
19190 - 1
19190 - 11
19190 - 21
19190 - 31
19190 - 41
19190 - 51
19190 - 61
19190 - 71
19190 - 81

2コアマシンで実行する場合seqsplitおよびwcプロセスはコアを共有します。よく見ると、システムは最初の2つのプロセスをCPU0に残し、CPU1をワーカープロセスに分割します。

%Cpu0  : 47.2 us, 13.7 sy,  0.0 ni, 38.1 id,  1.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 15.8 us, 82.9 sy,  0.0 ni,  1.0 id,  0.0 wa,  0.3 hi,  0.0 si,  0.0 st
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
 5314 lserni    20   0  4516  568  476 R 23.9  0.0   0:03.30 seq
 5315 lserni    20   0  4580  720  608 R 52.5  0.0   0:07.32 split
 5317 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5318 lserni    20   0  4520  572  484 S 14.0  0.0   0:01.88 wc
 5319 lserni    20   0  4520  576  484 S 13.6  0.0   0:01.88 wc
 5320 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.85 wc
 5321 lserni    20   0  4520  572  484 S 13.3  0.0   0:01.84 wc
 5322 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5323 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5324 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.87 wc

特にsplit、かなりの量のCPUを消費していることに注意してください。これは、Aのニーズに比例して減少します。つまり、Aがよりも重いプロセスである場合seq、の相対的なオーバーヘッドsplitは減少します。しかし、Aが非常に軽量なプロセスであり、Bが非常に高速な場合(Aと一緒に保持するために2〜3個のBしか必要ない場合)、並列化split(または一般的なパイプ)価値がないかもしれません。


興味深いことに、Ubuntuで見つかった分割には--filterオプションがありません。これにはどのようなOSを使用していますか?
-Jernej

Linux OpenSuSE 12.3、coreutils(gnu.org/software/coreutils/manual/html_node/…)。Ubuntuを手に入れようとしますが、似たような名前のツールに対応するために名前を変更した可能性があります。
LSerni

split --filter欠落しているオプションについて本当によろしいですか?私のUbuntu 12.04-LTS( "wheezy / sid")には、それがあり、私の例は動作します。splitGNU coreutilsのものとは異なるものをインストールできましたか?
LSerni

これをありがとう。Coreutilsの新しいバージョンをインストールする必要がありました。ところで、プログラムAを単独で実行すると、A |を実行するとコア全体(100%)を消費することに気付きました。Bが一緒にコア全体を食べ、プロセスAが15%を食べ、プロセスBが85%を食べます。これがなぜそうなのかわかりますか?
Jernej

2
これは、ブロッキングが原因である可能性があります。BがAよりも重い場合、Aは出力を送信できず、速度が低下します。もう1つの可能性は、A その操作中にBに譲歩することです(たとえば、ディスク/ネット)。別のシステムでは、BがCPU1の100%をゴブリングし、AがCPU0の18%を割り当てられていることがあります。おそらく、単一のAインスタンスを取得して単一のコアを飽和させるには、85/15〜5.67 = 5〜6のBインスタンスが必要です。ただし、I / Oが存在する場合、これらの値が歪む可能性があります。
LSerni
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.