Bash
如何為此用途優化 GNU 並行?
我出於無聊創建了這個腳本,其唯一目的是使用/測試 GNU 並行,所以我知道它不是特別有用或優化,但我有一個腳本可以計算所有質數,直到 n:
#!/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
我希望用 GNU 並行替換 for 循環會使它執行得更快,但這不是我的經驗。平均而言,它只快了大約 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
GNU Parallel 每個作業花費 2-10 毫秒的成本。可以通過使用降低一點
-u
,但這意味著您可能會從不同的工作中獲得混合輸出。如果您的工作在 ms 範圍內並且執行時很重要,那麼 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