Bash

dash 或其他一些 shell 是否比 bash“更快”?

  • March 1, 2021

我一直認為使用 dash 而不是 bash 的唯一好處是 dash 更小,因此許多 dash 實例在啟動時會啟動得更快。

但是我做了一些研究,發現有些人將他們所有的腳本遷移到 dash 以希望它們執行得更快,我還在Ubuntu Wiki的文章DashAsBinSh中發現了這一點:

切換預設 shell 的主要原因是效率。bash 是一個適合互動式使用的優秀的全功能 shell;實際上,它仍然是預設的登錄 shell。但是與dash相比,它的啟動和執行速度都比較大,速度也比較慢。

現在我已經在我的系統上使用了很多 bash 腳本,我的問題是我有一個特定的腳本,我每天 24/7 連續執行,它產生了大約 200 個孩子,它們一起加熱我的電腦 10° C 多於正常使用。

這是一個相當大的腳本,有很多 bashism,因此將它們移植到 POSIX 或其他一些 shell 將非常耗時(而且 POSIX 對於個人使用並不重要),但如果我可以減少其中的一些,那將是值得的CPU使用率。我知道還有其他事情需要考慮,比如呼叫一個外部二進製文件,比如sed一個簡單的 bashism,比如${foo/bar},或者grep代替=~.

TL;DR與 dash 相比,bash 的啟動**和執行速度真的慢嗎?**還有其他比 bash更有效的 Unix shell 嗎?

外殼序列:

可能對 shell 的性能進行基準測試的一種有用方法是重複進行許多非常小的、簡單的評估。我認為,重要的是不僅要循環,還要循環輸入,因為 shell 需要讀取<&0.

我認為這將補充@cuonglm 已經發布的測試,因為它展示了單個 shell 程序在呼叫後的性能,而不是他的展示了 shell 程序在呼叫時載入的速度。這樣,在我們之間,我們覆蓋了硬幣的兩面。

這是一個便於展示的函式:

sh_bench() (                                               #dont copy+paste comments
   o=-c sh=$(command -v "$1") ; shift                     #get shell $PATH; toss $1
   [ -z "${sh##*busybox}" ] && o='ash -c'                 #cause its weird
   set -- "$sh" $o "'$(cat <&3)'" -- "$@"                 #$@ = invoke $shell
   time env - "$sh" $o "while echo; do echo; done|$*"     #time (env - sh|sh) AC/DC
) 3<<-\SCRIPT                                                                      
#Everything from here down is run by the different shells    
   i="${2:-1}" l="${1:-100}" d="${3:-                     
}"; set -- "\$((n=\$n\${n:++\$i}))\$d"                     #prep loop; prep eval
   set -- $1$1$1$1$1$1$1$1$1$1                            #yup
   while read m                                           #iterate on input
   do  [ $(($i*50+${n:=-$i})) -gt "$(($l-$i))" ] ||       #eval ok?
           eval echo -n \""$1$1$1$1$1"\"                  #yay!
       [ $((n=$i+$n)) -gt "$(($l-$i))" ] &&               #end game?
           echo "$n" && exit                              #and EXIT
       echo -n "$n$d"                                     #damn - maybe next time
   done                                                   #done 
#END
SCRIPT                                                     #end heredoc

它要麼在每次換行讀取時增加一個變數,或者作為輕微優化,如果可以的話,它在每次換行讀取時增加 50 次。每次變數遞增時,它都會列印到stdout. 它的行為很像一種seqcross nl

並且只是為了清楚地說明它的作用 -這是在上面的函式set -x;之前插入它之後的一些截斷輸出time

time env - /usr/bin/busybox ash -c '
    while echo; do echo; done |
    /usr/bin/busybox ash -c '"'$(
        cat <&3
    )'"' -- 20 5 busybox'

所以每個shell首先被稱為:

env - $shell -c "while echo; do echo; done |..."

…生成它在讀入時需要循環的輸入3<<\SCRIPT- 或者cat無論如何。另一方面,|pipe它再次稱自己為:

"...| $shell -c '$(cat <<\SCRIPT)' -- $args"

所以除了最初的呼叫之外env (因為cat實際上是在上一行呼叫的);從它被呼叫到它退出,沒有其他程序被呼叫。至少,我希望這是真的。

數字前…

我應該對可移植性做一些說明。

  • posh不喜歡$((n=n+1))並堅持$((n=$n+1))
  • mksh在大多數情況下沒有printf內置函式。早期的測試讓它滯後了很多——它在/usr/bin/printf每次執行時都會呼叫。因此echo -n以上。
  • 也許更多,因為我記得它…

無論如何,對於數字:

for sh in dash busybox posh ksh mksh zsh bash
do  sh_bench $sh 20 5 $sh 2>/dev/null
   sh_bench $sh 500000 | wc -l
echo ; done

這將讓他們一口氣…

0dash5dash10dash15dash20

real    0m0.909s
user    0m0.897s
sys     0m0.070s
500001

0busybox5busybox10busybox15busybox20

real    0m1.809s
user    0m1.787s
sys     0m0.107s
500001

0posh5posh10posh15posh20

real    0m2.010s
user    0m2.060s
sys     0m0.067s
500001

0ksh5ksh10ksh15ksh20

real    0m2.019s
user    0m1.970s
sys     0m0.047s
500001

0mksh5mksh10mksh15mksh20

real    0m2.287s
user    0m2.340s
sys     0m0.073s
500001

0zsh5zsh10zsh15zsh20

real    0m2.648s
user    0m2.223s
sys     0m0.423s
500001

0bash5bash10bash15bash20

real    0m3.966s
user    0m3.907s
sys     0m0.213s
500001

任意 = 也許可以?

儘管如此,這是一個相當隨意的測試,但它確實測試了讀數輸入、算術評估和變數擴展。也許不全面,但可能接近那裡。

由 Teresa e Junior 編輯:@mikeserv 和我做了許多其他測試(請參閱我們的聊天以了解詳細資訊),我們發現結果可以總結如下:

  • 如果您需要速度,請務必使用dash,它比任何其他 shell 都快得多,並且比bash快 4 倍。
  • 雖然busybox的 shell 可能比dash慢得多,但在某些測試中它可能更快,因為它有許多自己的使用者空間實用程序,如grepsedsort等,它們沒有常用的 GNU 那麼多的特性實用程序,但可以盡可能多地完成工作。
  • 如果速度不是您關心的一切,那麼ksh(或ksh93)可以被認為是速度和功能之間的最佳折衷方案。它的速度與較小的mksh 相比,後者比bash快得多,並且它還具有一些獨特的功能,例如浮點運算
  • 儘管bash以其簡單性、穩定性和功能性而聞名,但在我們的大多數測試中,它是所有 shell 中最慢的,而且差距很大。

引用自:https://unix.stackexchange.com/questions/148035