私のディレクトリには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つをトリガーできることを知りました。したがって、同時に処理する4つのスクリプトインスタンスがありました。これらの画像と作業は1/4だけ上がった。
2番目の問題は、画像と配置を分割し、スクリプトを4つのディレクトリにコピーし、4つの端末ウィンドウを開くなどの作業に時間を無駄にしたことです。
何も分割せずにスクリプトでこれを達成するにはどうすればよいですか?
私の言葉は二つを意味します。まず、bashスクリプトからバックグラウンドでプロセスを開始する方法は? (最後に&?のみを追加してください。)2番目:4番目のジョブを送信した後にバックグラウンドでジョブの転送を停止し、スクリプトがジョブの終了を待つようにするにはどうすればよいですか。つまり、1つのタスクが終わったら、バックグラウンドで新しいタスクを送信し、常に4つのタスクを並列に保つことを意味しますか?そうしないと、ループは多数のタスクをバックグラウンドに送信し、CPUが詰まってしまいます。
答え1
xargs
並列実行をサポートするレプリカがある場合は、-P
単に次のことができます。
printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}
他のアイデアについてはWooledge Bash Wikiにあります。部分プロセス管理の記事で必要な内容を正確に説明します。
答え2
すでに提案されているソリューションに加えて、圧縮されていないファイルから圧縮ファイルを生成する方法を説明するmakefileを作成し、それを使用してmake -j 4
4つのタスクを並列に実行できます。問題は、圧縮ファイルと圧縮されていないファイルの名前を別々に指定するか、別のディレクトリに保存する必要があることです。そうでなければ、合理的なmakeルールを書くことは不可能です。
答え3
GNU並列がある場合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
答え4
2つの質問に答えるには:
- はい、行の末尾に&を追加すると、シェルにバックグラウンドプロセスを開始するように指示します。
- この
wait
コマンドを使用すると、続行する前にバックグラウンドのすべてのプロセスが完了するのを待つようにシェルに要求できます。
j
以下は、バックグラウンドプロセスの数を追跡するために変更されたスクリプトです。この値に達すると、NB_CONCURRENT_PROCESSES
スクリプトはj
ゼロにリセットされ、実行を再開する前にすべてのバックグラウンドプロセスが完了するのを待ちます。
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