35

同様の質問がいくつかありましたが、私の問題は「複数のプログラムを並行して実行する」ことではありません。これは、parallelまたはで簡単に実行できますxargs

Bash 関数を並列化する必要があります。

次のようなコードを想像してみましょう。

for i in "${list[@]}"
do
    for j in "${other[@]}"
    do
    # some processing in here - 20-30 lines of almost pure bash
    done
done

一部の処理では、外部プログラムへの呼び出しが必要です。

いくつか (4-10) のタスクを実行したいと思います$i。$list の要素の総数が 500 を超えています。

ループ全体for j ... doneを外部スクリプトに入れ、このプログラムを並行して呼び出すことができることはわかっていますが、機能を 2 つの別々のプログラムに分割せずに実行することは可能ですか?

4

3 に答える 3

52

semGNU Parallelの一部であり、この種の状況のた​​めに作られています。

for i in "${list[@]}"
do
    for j in "${other[@]}"
    do
        # some processing in here - 20-30 lines of almost pure bash
        sem -j 4 dolong task
    done
done

関数の方が気に入った場合は、GNU Parallel で二重の for ループを一度に実行できます。

dowork() { 
  echo "Starting i=$1, j=$2"
  sleep 5
  echo "Done i=$1, j=$2"
}
export -f dowork

parallel dowork ::: "${list[@]}" ::: "${other[@]}"
于 2013-06-26T09:27:35.400 に答える
9

複数行のコマンドを並行して実行できる効率的なソリューション:

for ...your_loop...; do
  if test "$(jobs | wc -l)" -ge 8; then
    wait -n
  fi

  {
    command1
    command2
    ...
  } &
done
wait

あなたの場合:

for i in "${list[@]}"
do
  for j in "${other[@]}"
  do
    if test "$(jobs | wc -l)" -ge 8; then
      wait -n
    fi

    {
      your
      commands
      here
    } &
  done
done
wait

すでに 8 つの bash ジョブが実行waitされている場合、少なくとも 1 つのジョブが完了するまで待機します。ジョブが少ない場合は、新しいジョブを非同期で開始します。

このアプローチの利点:

  1. 複数行のコマンドは非常に簡単です。すべての変数はスコープ内で自動的に「キャプチャ」されるため、引数として渡す必要はありません
  2. 比較的速いです。たとえば、これを並列と比較してください(公式を引用していmanます):

parallel は起動が遅く、最初は約 250 ミリ秒、その後は 150 ミリ秒かかります。

  1. 働く必要bashがあるだけです。

欠点:

  1. 数えたら8件あった可能性もあるけど、待ち始めたらもっと減ってた。(ジョブが 2 つのコマンドの間のミリ秒単位で終了した場合に発生します。) これによりwait、必要なジョブ数よりも少ないジョブ数になる可能性があります。ただし、少なくとも 1 つのジョブが完了すると再開されます。実行中のジョブが 0 の場合はすぐに再開されます (wait -nこの場合はすぐに終了します)。
  2. &同じ bash スクリプト内で非同期 ( ) で実行されているコマンドが既にいくつかある場合は、ループ内のワーカー プロセスが少なくなります。
于 2018-01-11T18:48:11.977 に答える