4つのタスクを並行して…どうすればいいですか?


23

ディレクトリに多数のPNGイメージがあります。これらの画像を圧縮するために実行するpngoutというアプリケーションがあります。このアプリケーションは、私がやったスクリプトによって呼び出されます。問題は、このスクリプトが次のように一度に1つずつ実行することです。

FILES=(./*.png)
for f in  "${FILES[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 $f R${f/\.\//}
done

一度に1つのファイルのみを処理するには、多くの時間がかかります。このアプリを実行した後、CPUがわずか10%であることがわかります。そのため、これらのファイルを4つのバッチに分割し、各バッチをディレクトリに入れて、4つのターミナルウィンドウ、4つのプロセスから4を起動できることを発見しました。ジョブは時間の1/4かかります。

2番目の問題は、イメージとバッチを分割し、スクリプトを4つのディレクトリにコピーして、4つのターミナルウィンドウを開き、bla bla ...

何も分割せずに、1つのスクリプトでそれをどのように行いますか?

私は2つのことを意味します:最初にbashスクリプトからどのようにバックグラウンドにプロセスを起動しますか?(最後に追加するだけですか?)2番目:4番目のタスクを送信した後、バックグラウンドへのタスクの送信を停止し、タスクが終了するまでスクリプトを待機させるにはどうすればよいですか?つまり、1つのタスクが終了すると新しいタスクをバックグラウンドに送信するだけで、常に4つのタスクを並行して保持しますか?そうしないと、ループは何十億ものタスクをバックグラウンドで起動し、CPUが詰まります。


回答:


33

xargs並列実行をサポートするコピーをお持ちの場合は、-P単に行うことができます

printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}

その他のアイデアについては、Wooledge Bash wiki にはProcess Managementの記事に必要なものを正確に説明するセクションがあります。


2
この場合のために設計された「gnu parallel」と「xjobs」もあります。それは主に好みの好みの問題です。
-wnoise

提案されたコマンドについて説明してください。ありがとう!
ユージンS

1
@EugeneSどの部分についてもう少し詳しく教えてください。printfはすべてのpngファイルを収集し、パイプを介してxargsに渡します。xargsは、標準入力から引数を収集しpngout、OPが実行したいコマンドの引数に結合します。重要なオプションは-P 4、最大4つの同時コマンドを使用するようにxargsに指示します。
jw013

2
正確ではないので申し訳ありません。なぜprintf通常の機能ではなく、ここで関数を使用したのls .. | grep .. *.pngでしょうか。また、xargs使用したパラメーター(-0および-I{})にも興味がありました。ありがとう!
ユージンS

3
@EugeneS最大の正確さと堅牢性のためです。ファイル名は行ではなく、lsファイル名を移植可能かつ安全に解析するために使用することはできません。区切るよう、ファイル名に使用する唯一の安全な文字がある\0/、を含む他のすべての文字、以降\n、ファイル名自体の一部にすることができます。printf用途\0の範囲を定めるのファイル名に、と-0知らせるxargsこのの。-I{}告げるxargs交換する{}引数で。
jw013

8

既に提案されているソリューションに加えて、非圧縮ファイルから圧縮ファイルを作成する方法を記述したメイクファイルを作成し、make -j 44つのジョブを並行して実行するために使用できます。問題は、圧縮ファイルと非圧縮ファイルに異なる名前を付けるか、異なるディレクトリに保存する必要があることです。そうしないと、合理的なmakeルールを書くことができなくなります。


7

GNU Parallel http://www.gnu.org/software/parallel/がインストールされている場合、これを行うことができます。

parallel ./pngout -s0 {} R{} ::: *.png

GNU Parallelは次の方法で簡単にインストールできます。

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem

詳細については、GNU Parallelのイントロビデオをご覧くださいhttps : //www.youtube.com/playlist?list=PL284C9FF2488BC6D1


5

2つの質問に答えるには:

  • はい、行の最後に&を追加すると、バックグラウンドプロセスを起動するようシェルに指示されます。
  • waitコマンドを使用して、バックグラウンドのすべてのプロセスが終了するのを待ってから先に進むようにシェルに要求できます。

これjは、バックグラウンドプロセスの数を追跡するために使用されるように変更されたスクリプトです。ときにNB_CONCURRENT_PROCESSES到達し、スクリプトがリセットされj0にし、それの実行を再開する前にフィニッシュにすべてのバックグラウンド・プロセスを待ちます。

files=(./*.png)
nb_concurrent_processes=4
j=0
for f in "${files[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 "$f" R"${f/\.\//}" &
        ((++j == nb_concurrent_processes)) && { j=0; wait; }
done

1
これは、4つの並行プロセスの最後を待ってから、さらに4つのセットを開始します。おそらく、4つのPIDの配列を作成してから、これらの特定のPIDを待つ必要がありますか?
ニルス

コードに対する私の修正を説明するために:(1)スタイルの問題として、大文字の変数名はすべて内部シェル変数と競合する可能性があるため、すべて避けてください。(2)$fなどの引用符を追加しました。(3)[POSIX互換スクリプトに使用しますが、純粋なbashに[[は常に優先されます。この場合、((算術により適しています。
jw013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.