276
253

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

シェルで変数のインクリメントに expr を使うと100倍遅い件

Last updated at Posted at 2014-12-27

シェルプログラミングにおいて、ループカウンタなどをインクリメントするとき、どのようにしますか?

いきなりですがサンプルから。

#!/bin/bash

COUNT=0

while [ $COUNT -lt 1000 ]; do
    
    # 何かの処理

    COUNT=`expr $COUNT + 1` # COUNT をインクリメント
done

expr コマンドを使う?

シェルプログラミングの入門記事などを見ると、変数のインクリメントに上記のような COUNT=`expr $COUNT + 1` を用いているものが多くあります。
しかし、この書き方は とても遅い です。空のループを1000回繰り返すだけでも手元の mac (Core i7) で約2秒もかかってしまいました。

$ time bash shelltest.sh

real	0m1.939s
user	0m0.791s
sys	0m1.098s

二重括弧 ((...)) を使う!

Bash では expr の代わりに二重括弧を用いて算術式を評価することができます。評価した値を取り出したいときは二重括弧の前に$をつけて $((...)) とします。つまり、

(( COUNT++ )) # COUNT をインクリメント

または、少し明示的に

COUNT=$(( COUNT + 1 )) # COUNT をインクリメント

とします。こちらを使ったほうが 圧倒的に速い です。
最初のサンプルのインクリメント部分だけをこれに変えたプログラム

#!/bin/bash

COUNT=0

while [ $COUNT -lt 1000 ]; do
    
    # 何かの処理

    COUNT=$(( COUNT + 1 )) # COUNT をインクリメント
done

を実行してみると、

$ time bash shelltest2.sh

real	0m0.016s
user	0m0.014s
sys	0m0.002s

と、 100倍以上の速さ になっています。

汎用性?

いちおう、最初のexpr を使う書き方のほうが汎用性が高いみたいです。Solaris とかのシェルでも使える?
そっち系のシェルでは二重括弧が使えないものがあるとか。

ただ、現在のところ広く使われている CentOS や、mac でもデフォルトのシェルが bash になっていますし、あまり調べていないけど他の zsh とかのシェルでも二重括弧はある程度使えそうなのかな?と言った印象です。(zsh では少なくとも上のスクリプトは実行できました。)

bashを使っているなら、 何が何でも汎用性を保ちたい!ということでなければ後者の二重括弧を使うほうがよい と思います。

expr はなぜ遅いのか?

さて、今回の実験ではたった1000回のループしか行なっていないので二重括弧が速いというよりも expr がインクリメントの処理としては尋常ではなく遅い 、というべきでしょう。これはなぜでしょうか?

コマンドだから fork が遅い

これもあまり詳しくは調べていないのですが、自分の理解の範囲で。

 COUNT=`expr $COUNT + 1`

と、右辺をバッククォートでくくっていることから、 expr はコマンド扱いですよね。実際、コマンドラインから expr というコマンドを実行することもできますしね。

以前偉い人から聞いた話では、このような場合この expr コマンドは別プロセスを立ちあげて実行される、とのことでした。つまり プロセスの fork が必要です。fork のコストは相当高いです。変数に1足すためだけにわざわざ別プロセスを fork するなんていかにも大げさですよね。牛刀を以ってなんとやら、な感じです。

Cygwin だとさらにやばい

昨今では使う人は減っているのかもしれませんが、Windows 上で Linux 環境をエミュレートする Cygwin では fork のコストがさらに桁違いらしいです。
いま手元にないので試せませんが、以前にやった時には普通の Linux に比べて10倍くらい遅かった覚えがあります。二重括弧式と比べると 1000倍の遅さ です!これはちょっと使っていられないでしょうね・・・

参考

276
253
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
276
253

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?