web-dev-qa-db-ja.com

Bash:プロセスの修正番号を待ちます

Java jarをnの回数実行するbashスクリプトを作成しました。

実際には、jarの呼び出しを含むe foo()関数を定義してから、次のスクリプトを実行します。

for RUN in $(seq 1 $RUNS) 
do 
    foo & 
done

runsjarを並列実行しないようにしたいと思います。並列実行の数を制限するための待機がありますか(たとえば、10プロセスごとにwaitのように)?

6
Giovanni Grano

bashバージョン4.4では、パラメータ変換と呼ばれる便利な新しいイディオムが導入され、この場合に役立ちます。以下のコードスニペットでは、${num_jobs@P}の使用に注意してください。 @Pパラメータ変換の一種であり、bashプロンプト文字列であるかのように変数を展開します。その他のパラメータ変換オプションについては、man bashを参照してください。

#!/bin/bash
num_procs=$1
num_iters=$2
num_jobs="\j"  # The Prompt escape for number of jobs currently running
for ((i=0; i<num_iters; i++)); do
  while (( ${num_jobs@P} >= num_procs )); do
    wait -n
  done
  foo &
done

https://stackoverflow.com/a/38775799/663181 のchepnerへのクレジット。


Kusalanandaのコメントに従い、必要に応じて、このプロセスのグループを、カウントに影響を与える他のバックグラウンドジョブから独立させるために、独自のシェルでラップすることができます。このため、いくつかの変更が必要です。

#!/bin/bash
# start a wrapper Shell for the group of jobs
cat<<EOS | bash &
num_procs="$1"
num_iters="$2"
for ((i=0; i<num_iters; i++)); do
  # escape what's not supposed to be expanded
  # at the time of here-doc redirection
  while (( \${num_jobs@P} >= num_procs )); do  
    wait -n
  done
  foo &
done
EOS
# now you can do other things
5
user147505
for RUN in $(seq 1 $RUNS); do
    foo &

    if (( (RUN % 10) == 0 )); then
        wait
    fi
done

または、代替のループ構造を使用して(見栄えの良いIMHO):

for (( r = 1; r <= RUNS; ++i )); do
    foo &

    if (( (r % 10) == 0 )); then
        wait
    fi
done

ループの後にwaitを追加したい場合は、$RUNSは10の倍数ではありません。


実行する実行の総数としてRUNSを使用する代わりに、10個のジョブのnバッチを使用することもできます。

for (( i = 0; i < n; ++i )); do
    printf 'starting batch %d...\n' "$i"
    for (( j = 0; j < 10; ++j )); do
        foo &
    done

    echo 'waiting...'
    wait
done

xargsを使用し、明示的なwaitを使用しない代替ソリューション:

seq 1 "$RUNS" | xargs -n 1 -P 10 foo

ただし、これはfooプロセスに不要なコマンドライン引数(seqによって生成される整数の1つ)を与えることになります。これはその問題を取り除きます:

seq 1 "$RUNS" | xargs -n 1 -P 10 sh -c 'foo'
3
Kusalananda

GNU Parallelはまさにこれのために作られています:

seq 1 $RUNS | parallel -j 10 -N0 foo

デフォルトでは、CPUコアごとに1つのジョブを実行します。

seq 1 $RUNS | parallel -N0 foo

GNU Parallelは、一般的なパラレライザーであり、同じマシン上で、またはsshにアクセスできる複数のマシン上で、ジョブを簡単に並列実行できます。

4つのCPUで実行する32の異なるジョブがある場合、並列化する簡単な方法は、各CPUで8つのジョブを実行することです。

Simple scheduling

代わりに、GNU Parallelは、プロセスが終了すると新しいプロセスを生成します-CPUをアクティブに保ち、時間を節約します。

GNU Parallel scheduling

インストール

セキュリティ上の理由から、パッケージマネージャとGNU Parallelをインストールする必要がありますが、GNU Parallelがディストリビューションにパッケージ化されていない場合は、個人用インストールを実行できます。 rootアクセスは必要ありません。これを行うと、10秒で実行できます。

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

他のインストールオプションについては http://git.savannah.gnu.org/cgit/parallel.git/tree/README を参照してください

詳細

その他の例を見る: http://www.gnu.org/software/parallel/man.html

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

チュートリアルをご覧ください: http://www.gnu.org/software/parallel/parallel_tutorial.html

サポートを受けるには、メーリングリストにサインアップしてください: https://lists.gnu.org/mailman/listinfo/parallel

2
Ole Tange