同様の質問がいくつかありましたが、私の問題は「複数のプログラムを並行して実行する」ことではありません。これは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つの別個のプログラム間で機能を分割せずに実行できますか?
編集:代わりに 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 "$@"' --
sem
は GNU 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[@]}"
複数行のコマンドを並行して実行するソリューション:
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つのジョブが完了するまで待機します。ジョブの数が少ない場合は、新しいジョブを非同期で開始します。
このアプローチの利点:
man
を引用しています):パラレルは起動時に遅くなります-最初の約250 msとその後150 ms。
bash
だけです。欠点:
wait
を実行できます。ただし、少なくとも1つのジョブが完了したとき、または実行中のジョブが0の場合はすぐに再開されます(この場合、wait -n
はすぐに終了します)。&
)が既にある場合は、ループ内のワーカープロセスが少なくなります。