web-dev-qa-db-ja.com

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

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

foo @ bar:〜$ A | B

これでコアが1つしか消費されないことに気づきました。したがって、私は不思議に思っています:

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

私が気づいたもう1つのことは、AがBよりもはるかに高速に実行されることです。

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

だから私の最後の質問は:

発生する可能性のある競合状態やその他の不整合を処理する必要なく、いくつかのBプロセス間で出力をAにパイプする方法はありますか?

17
Jernej

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

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

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

 A | B | C

しかし、そのBはひどく遅いので、それを並列化したいとします。次に、次のことができます。

A | parallel --pipe B | C

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

GNU Parallel at: http://www.gnu.org/s/parallel/ についての詳細を見つけることができます

あなたはGNU Parallelをわずか10秒でインストールできます:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 の紹介ビデオをご覧ください

15
Ole Tange

あなたが書くときA | B、両方のプロセスalready並列で実行されます。それらが1つのコアのみを使用しているように見える場合、それはおそらく、CPUアフィニティ設定(おそらく、異なるアフィニティのプロセスを生成するツールがある)か、1つのプロセスではコア全体を保持するのに十分ではなく、システムです。コンピューティングを広げないことを好む」。

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

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

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

他のオプションが存在します(たとえば、Bの各インスタンスを単一のラインバッファー出力に制限し、Bの「ラウンド」全体が終了するまで待って、同等のreducesplit 's map、および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に送信され、以下同様に続きます。さらに、2番目のプロセスを生成するためにsplitがかかる時間の中で、最初のプロセスはすでにクォータに適切な方法です。

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の相対的なオーバーヘッドは減少します。 But Aが非常に軽量なプロセスであり、Bが非常に高速である場合(Aに合わせてBを2〜3個以上保持する必要がない場合)、split(またはパイプ一般)might価値がない。

13
LSerni