web-dev-qa-db-ja.com

与えられた関数をBashで並列に実行する方法は?

同様の質問がいくつかありましたが、私の問題は「複数のプログラムを並行して実行する」ことではありません。これは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つの別個のプログラム間で機能を分割せずに実行できますか?

28
user80168

編集:代わりに Oleの回答 を検討してください。

別のスクリプトの代わりに、コードを別のbash関数に配置できます。次に、それをエクスポートして、xargsを介して実行できます。

#!/bin/bash
dowork() { 
    sleep $((RANDOM % 10 + 1))
    echo "Processing i=$1, j=$2"
}
export -f dowork

for i in "${list[@]}"
do
    for j in "${other[@]}"
    do
        printf "%s\0%s\0" "$i" "$j"
    done
done | xargs -0 -n 2 -P 4 bash -c 'dowork "$@"' -- 
15
that other guy

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[@]}"
42
Ole Tange

複数行のコマンドを並行して実行するソリューション:

for ...your_loop...; do
  test "$(jobs | wc -l)" -ge 8 && wait -n || true  # wait if needed

  {
    any bash commands here
  } &
done
wait

あなたの場合:

for i in "${list[@]}"
do
    for j in "${other[@]}"
    do
        test "$(jobs | wc -l)" -ge 8 && wait -n || true
        {
            your
            multi-line
            commands
            here
        } &
    done
done
wait

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

このアプローチの利点:

  1. 複数行コマンドの場合は非常に簡単です。すべての変数はスコープ内で自動的に「取得」され、引数として渡す必要はありません
  2. 比較的高速です。たとえば、これをパラレルと比較します(公式のmanを引用しています):

    パラレルは起動時に遅くなります-最初の約250 msとその後150 ms。

  3. 動作するのはbashだけです。

欠点:

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