2013-05-14 26 views
8

私は、主にコレクションの数学計算を実行するClojureScriptプログラムを持っています。それは慣用的な、ホストに依存しないClojureで開発されたので、ベンチマークするのは簡単です。驚いたことに(回答がWhich is faster, Clojure or ClojureScript (and why)?に示唆していることに反して)、ClojureScriptの同じコードは、Clojureの同等のコードより5〜10倍遅く実行されます。ClojureScriptプログラムのパフォーマンスを向上させる

ここに私がしたことがあります。私はlein replを開いて、ブラウザはhttp://clojurescript.net/に戻ります。次に、両方のREPLでこれらのスニペットを試しました。

(time (dotimes [x 1000000] (+ 2 8))) 

(let [coll (list 1 2 3)] (time (dotimes [x 1000000] (first coll)))) 

その後、私は戻るブラウザREPLに

function benchmark(count, fun) { 
    var t0 = new Date(); 
    for (i = 0; i < count; i++) { 
    fun(); 
    } 
    var t1 = new Date(); 
    return t1.getTime() - t0.getTime(); 
} 

、ブラウザのREPLでJavaScriptコンソールを開き、ミニマリストのベンチマーク機能を書いた:その後

(defn multiply [] (* 42 1.2)) 

両方のネイティブJavaScriptを試します乗算、およびそのクローズアップスクリプトの変形をjavacriptコンソールに表示します。

私は

  • ネイティブJavaScriptの数学を発見した何3210
    benchmark(1000000, cljs.user.multiply); 
    
    benchmark(1000000, function(){ 42 * 1.2 }); 
    

  • ClojureScriptは今私の質問は、どのように

あるそれらのいずれよりも5〜10倍遅いのClojureで数学に匹敵します私はClojureScriptプログラムのパフォーマンスを改善できますか?

私は

  • 、これまで考えられてきたいくつかのアプローチがありますが、バック舞台裏で変更可能なJavaScriptの配列やオブジェクトを使用する秋。 (これはまったく可能ですか?)
  • ネイティブのJavaScriptの数学演算子を使用することに戻ります。 https://github.com/chlorinejs/chlorineまたはhttps://github.com/gozala/wispのような彼らはより多くの慣用的なJavaScriptを生成するが、彼らは名前空間をサポートしていない明示的に(aget js/v 0)
  • との配列は、Clojureの-用-のjavascriptの少ない野心的な実装を使用するJavaScript(これがすべてでは可能ですか?)
  • 使用私はたくさん使っています。

答えて

10

JavaScriptがそう

function() { 42 * 1.2 } 

は何もしない、明示的なリターンを持っています。代わりにベンチマークする必要があります

function() { return 42 * 1.2 } 

これはまさにClojureScriptのバージョンがコンパイルされたものであるため、違いはありません(ClojureScriptでは、高次の使用法の基本的な算術関数は通常の演算子ベースのJavaScript式としてインライン展開されます)。

ここで、ClojureScriptはClojureScriptよりもはるかに高速です。その理由の1つは、ClojureScriptはこの部門のかなりのペースで改善していますが、ClojureScriptはClojureScriptよりも慎重にチューニングされているということです。もう一つの部分は、Clojureがより成熟したJITを利用することです(現代のJSエンジン、特にV8はかなり優れていますが、まだHotSpotグレードではありません)。

違いの大きさは測定するのがやや難しいですが、 JITが関与しているという事実は、疑問のような副作用のないボディーを持つループが、おそらく最初に実行されたときでさえ、(スタック上の置換を使用することによって)最適化される可能性が高いことを意味します、ホットスポットで使用されて私はもV8と思う - 確かに確認する必要があります)。だから、

(def arr (long-array 1)) 

;;; benchmark this 
(dotimes [_ 1000000] 
    (aset (longs arr) 0 (inc (aget (longs arr) 0)))) 

(Clojureので反射を避けるためにlongs呼び出し、また^longsヒントを使用することができます)などのベンチマーク何かに優れています。

最後に、ClojureとClojureScriptの両方で、特定の種類の特にパフォーマンスに影響を受けるコードでは、ネイティブ配列などを使用するのが最善のケースです。幸いなことに、そうすることには問題がありません:ClojureScript側では、あなたがarrayjs-objagetasetmake-arrayを持っている、あなたは、メソッド本体などにset!にできるようにdeftypeのフィールド上に:mutableメタデータを使用することができます

7

ClojureScriptの数学 JavaScript mathです。はい、パフォーマンスが重要な場合は、JavaScript配列と提供された低レベル演算子を使用します。これらは可能な限り最適なコードを生成することが保証されています(つまり高次の使用はありません)。 ClojureScriptの永続的なデータ構造は、配列の突然変異、算術演算、ビットの並び替えのように記述されています。

効率的なClojureScript - http://github.com/swannodette/cljs-stl/blob/master/src/cljs_stl/spectral/demo.cljsの小さな例がありますが、これは参考になるかもしれません。

+1

私はあなたがClojureScriptのどこかにスペクトル標準を持っていると思いました! +1する。 –

関連する問題