私はGNUパラレルを使用/テストするために退屈でこのスクリプトを作成しました。
#!/usr/bin/env bash
isprime () {
local n=$1
((n==1)) && return 1
for ((i=2;i<n;i++)); do
if ((n%i==0)); then
return 1
fi
done
printf '%d\n' "$n"
}
for ((f=1;f<=$1;f++)); do
isprime "$f"
done
ループを使用して実行する場合:
$ time ./script.sh 5000 >/dev/null
real 0m28.875s
user 0m38.818s
sys 0m29.628s
私はforループをGNU並列処理に置き換えると作業速度がはるかに速くなると期待していましたが、私の経験はそうではありませんでした。平均して約1秒ほど高速です。
#!/usr/bin/env bash
isprime () {
local n=$1
((n==1)) && return 1
for ((i=2;i<n;i++)); do
if ((n%i==0)); then
return 1
fi
done
printf '%d\n' "$n"
}
export -f isprime
seq 1 $1 | parallel -j 20 -N 1 isprime {}
並列実行:
$ time ./script.sh 5000 >/dev/null
real 0m27.655s
user 0m38.145s
sys 0m28.774s
私はこの関数を最適化することにあまり興味がありませんisprime()
。ちょうどGNUの並列性を最適化するために何かをすることができるかどうか疑問に思います。
私のテストでは、seq
実際には以下より速く実行されましたfor ((i=1...))
。
興味深いことに、forループを次のように変更すると:
for ((f=1;f<=$1;f++)); do
isprime "$f" &
done | sort -n
より速く実行されます。
$ time ./script.sh 5000 >/dev/null
real 0m5.995s
user 0m33.229s
sys 0m6.382s
ベストアンサー1
GNU Parallelには、ジョブあたり2〜10ミリ秒のオーバーヘッドがあります。を使用すると少し下げることができますが、-u
これは他のジョブの出力を混在させることができます。
タスクがミリ秒の範囲内にあり、ランタイムが重要である場合、GNU Parallelは理想的ではありません。通常、オーバーヘッドが大きすぎます。
複数のGNU Parallelsを実行して、複数のコアにオーバーヘッドを分散させることができます。
seq 5000 | parallel --pipe --round-robin -N100 parallel isprime
それでもオーバーヘッドを支払う必要がありますが、今は少なくとも支払うべきコアが増えました。
isprime
より良いアプローチは、複数の入力が必要なため、実行に時間がかかるように変更することです。
isprime() {
_isprime () {
local n=$1
((n==1)) && return 1
for ((i=2;i<n;i++)); do
if ((n%i==0)); then
return 1
fi
done
printf '%d\n' "$n"
}
for t in "$@"; do
_isprime $t
done
}
export -f isprime
seq 5000 | parallel -X isprime
# If you do not care about order, this is faster because higher numbers always take more time
seq 5000 | parallel --shuf -X isprime