真面目に、強く、上品に

たのしく、げんきに

Clojureのevalとmacroのパフォーマンスを比べる

Clojureには他の動的型言語と同様に文字列*1をプログラムとして評価出来るevalという関数があります。 Clojureにはマクロがありますし他の動的型言語と同様にevalは遅いだろうという推測は容易に出来ますので、evalを使わないといけない局面というのはそう多くないと思います。そもそもeval自体害悪であるとも考えられます。

ただプログラムを書いていてふとevalはどの程度遅いのかということが気になったので簡単に計測してみました。

clojureのevalとmacroで実行時間を比較

bashpythonclojure3つの言語が混在していますが、 10 * 10をeval版、macro版、関数版で10000回実行するプログラムを、20回実行しその平均を取っています。 dotimesはdotimesだけでどれぐらいの時間がかかるのかを計測するために入れています。

結果以下のようになりました。(単位はms)

eval: 8666.7311
macro: 2.3436
fn: 7.67685
dotimes: 0.896

実行時の環境、evalする対象、macroにする対象によって数値は多少変わるとは思いますが、 見て分かる通りmacro版、関数版に比べてeval版は1000倍以上遅いです。

あと関数版とマクロ版を比べたらマクロ版の方が早いように思いますが、 これはマクロが呼び出し元で展開され実行されるのに対して、関数版はユーザ定義の関数を呼び出さなければならないことによるものでしょう。 この辺り、ベンチマーク自体が即席のものであり、また実行時間も短いので、信頼性の高いものではありません。この辺りはちゃんと検証する必要があります。

ただ数回実行する即席で実行するプログラムならまだしも、同じような処理が走りパフォーマンスが重要になるような局面ではevalは絶対に使えないとは言えると思います。

*1:Clojureについてはクオートされている必要がある