拡張 POSIX シェルスクリプト Advent Calendar 2013、 1日目の記事です。
「このくらいの要件ならシェルで書ける!」と意気込んで実装を開始して、 たとえやりきっても「あー、やっぱり (あなたの好きな LL) で書けばよかった」 なんてことありませんか? 私はあまりありません。 POSIX シェルやそれ以前の非力なシェルはともかく、bash や ksh、zsh のような拡張 POSIX シェルであれば、少し無理をすれば、大抵の処理は書けます。 老害ですね、わかります。
しかし実装は問題ないのですが、速度がいまひとつなのはどうしても否めません。 そこで一つ、少しでも実行速度を改善する簡単な方法を伝授しましょう。 それは「bash は避ける」です。
過去の経験から bash が遅いということに気付いていたのですが、 今回はベンチマークを取ることで検証してみました。
環境:
$ grep 'model name' /proc/cpuinfo |head -n1
model name : Intel(R) Core(TM) i7-2620M CPU @ 2.70GHz
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux unstable (sid)
Release: unstable
Codename: sid
$ bash --version |head -n1
GNU bash, バージョン 4.2.45(1)-release (x86_64-pc-linux-gnu)
$ ksh --version
version sh (AT&T Research) 93u+ 2012-08-01
$ zsh --version
zsh 5.0.2 (x86_64-pc-linux-gnu)
結果: 各数値は「秒数 (bash比)」です。
$ zsh ./sh-benchmark.zsh
| bash | ksh | zsh |
| 0.32 ( 100.0) | 0.06 ( 18.9) | 0.05 ( 16.0) | Parameter Expansion 1: "$PARAMETER"
| 0.91 ( 100.0) | 0.11 ( 12.2) | 0.10 ( 11.0) | Parameter Expansion 2: $PARAMETER
| 4.61 ( 100.0) | 2.34 ( 50.8) | 3.08 ( 67.0) | Parameter Expansion 3: "${PARAMETER##*/}" (modifier)
| 5.43 ( 100.0) | 0.10 ( 1.8) | 78.74 (1449.0) | Array Parameter Expansion 1: "${ARRAY[1]}" (one element)
| 7.08 ( 100.0) | 0.63 ( 8.9) | 11.12 ( 157.2) | Array Parameter Expansion 2: "${ARRAY[@]}" (all elements)
| 13.19 ( 100.0) | 11.37 ( 86.2) | 6.31 ( 47.8) | Arithmetic Evaluation 1: let EXPRESSION
| 9.32 ( 100.0) | 4.65 ( 49.9) | 3.33 ( 35.8) | Arithmetic Evaluation 2: ((EXPRESSION))
| 13.02 ( 100.0) | 9.97 ( 76.6) | 4.82 ( 37.0) | Arithmetic Expansion 1: $((EXPRESSION))
| 16.67 ( 100.0) | 10.86 ( 65.2) | 5.31 ( 31.9) | Arithmetic Expansion 2: $(($PARAMETER+EXPRESSION))
| 6.53 ( 100.0) | 3.50 ( 53.6) | 2.38 ( 36.5) | Test 1: [[ EXPRESSION ]]
| 16.13 ( 100.0) | 4.20 ( 26.0) | 10.30 ( 63.8) | Test 2: [ EXPRESSION ]
| 6.65 ( 100.0) | 38.53 ( 579.3) | 5.63 ( 84.6) | Fork
| 13.76 ( 100.0) | 7.96 ( 57.8) | 14.48 ( 105.2) | Fork & Exec
| 2.91 ( 100.0) | 0.21 ( 7.2) | 1.77 ( 60.9) | Iterate Parameters 1; for
| 29.57 ( 100.0) | 0.08 ( 0.3) | 5.18 ( 17.5) | Iterate Parameters 2: while shift
| 72.66 ( 100.0) | 0.19 ( 0.3) | 5.65 ( 7.8) | Iterate Parameters 3: while ((n++<$#))
ksh は fork 以外 (プロセス置換以外かも)、zsh は配列パラメーターの展開以外、 bash より高速であることがわかりました。
各ベンチマークの内容: sh-benchmark-scripts.sh
変なところに bash, ksh, zsh の違いがあったり、
{1..1000000}
の右辺を増やしすぎると ksh が Memory fault
と言って死んだり、
意外と作るのに苦労しました。
ベンチマークの前処理で $(zsh -c "echo {1..1000000}")
のように一部
zsh を利用していますが、これは今回利用した bash 4.2 に
{1..1000000}
に絡む処理をやらせた場合に、異様に遅い問題があったためです。
たとえば次の例を実行したとき数分待っても終わらないんですが。
bash 3.0, 3.2, 4.1 では数秒で終了します。
$ time bash -c 'i=( {1..1000000} );'
ベンチマークスクリプト: sh-benchmark.zsh
ところで、12月25日はクリスマスな上に、
OSS 界隈で地味に活躍されているふみやすさんの誕生日ですね!
っ http://www.amazon.co.jp/registry/wishlist/27M7TV8CEEF6G?sort=priority
逆に、あなたの書いた OSS や Blog や Advent Calendar が気に入ったら何か送りたく なってしまうかもしれないので、プロフィールや Web サイトに あなたの Amazon 欲しいものリストの URL を貼っておいてくださいね!
私が勤める OSSTech っていう某弊社で社員募集しているようです。 人材紹介会社を介さなければ、入社後に 20万円のボーナス! 「ふみやすっていう人に紹介された」と言ってもらえると私にもボーナス!! → https://www.osstech.co.jp/recruit/
よろしければ、これまで参加した/参加予定のほかの Advent Calendar もどうぞ。
- Ansible Advent Calendar 2023
- シェル芸 Advent Calendar 2023
- 闇の魔術に対する防衛術 Advent Calendar 2023
- Ansible Advent Calendar 2023
- Ansible Advent Calendar 2020
- DNS温泉 Advent Calendar 2019
- OSSTech Advent Calendar 2019
- Ansible Advent Calendar 2018
- OSSTech Advent Calendar 2018
- Debian/Ubuntu Advent Calendar 2017
- Linux Advent Calendar 2017
- Shell Script Advent Calendar 2017
- Shell Script Advent Calendar 2016
- OpenLDAP と仲間たち Advent Calendar 2015
- Postfix Advent Calendar 2014
- 拡張 POSIX シェルスクリプト Advent Calendar 2013