2013-05-20 30 views
4

我有一個簡單的地圖:ClojureScript地圖查找慢

(def my-map 
    {[1 2 3] 1 
    [1 2 4] 5 
    [3 4 2] 3 
    [4 5 3] 3 
    [5 2 5] 6 
    [9 2 1] 5 
    [8 3 1] 6}) 

,我使用的執行查找。這將執行相當差,但是:

(time (doseq [x (range 500)] 
     (my-map [1 2 8]))) 

"Elapsed time: 170 msecs" 

在同一臺機器上的Clojure可以在大約236毫秒做500,000,或約700X更快。雖然Clojure比ClojureScript更快並不意外,但我很困惑爲什麼ClojureScript會慢得多。

有關如何在ClojureScript中有效地以可讀方式創建簡單的多值查找映射的任何想法?我知道做一堆if而不是使用vector-key解決方案肯定會更快,但我正在尋找一些更易讀/可維護的東西。

只是爲了更新信息。以上是在Firefox中完成的,因此比起V8慢。以下:

(def my-map2 
    (into cljs.core.PersistentHashMap/EMPTY 
     {[1 2 3] 1 
     [1 2 4] 5 
     [3 4 2] 3 
     [4 5 3] 3 
     [5 2 5] 6 
     [9 2 1] 5 
     [8 3 1] 6})) 

(defn p1 [] 
    (let [v [1 2 8]] 
    (dotimes [_ 5] 
     (time (dotimes [_ 500000] 
       (get my-map2 v)))))) 

給出:

"Elapsed time: 3295 msecs" 

"Elapsed time: 3246 msecs" 

"Elapsed time: 3113 msecs" 

"Elapsed time: 3107 msecs" 

"Elapsed time: 3121 msecs" 
在Chromium版本25.0.1364.160的Ubuntu 13.04

(25.0.1364.160-0ubuntu3)。所以ClojureScript的速度仍然比Clojure慢13倍左右,但這比以前要好得多。還要注意,我直接在瀏覽器中運行這個代碼。

+0

是Firefox的滯後一點在ClojureScript性能方面是最好的。希望我們很快會向Mozilla提交基準代碼以幫助解決這個問題。由瀏覽器REPL生成的JavaScript代碼沒有完全優化,因爲它妨礙了開發。所以爲了真正衡量ClojureScript的性能,你需要使用高級編譯。 – dnolen

回答

7

在我的機器上運行具有高級編譯功能的精確示例,在我的1.7GHz Macbook Air上運行約14ms,運行的是從源代碼構建的相對較新的v8。

爲了確保我們標杆我們認爲我們正在標杆,最好寫的是這樣的:機器上

(let [v [1 2 8]] 
    (dotimes [_ 5] 
    (time 
     (dotimes [_ 500000] 
     (get my-map v))))) 

在我的機器這需要〜70ms的用於Clojure的JVM。 ClojureScript在〜3600ms左右運行,大約慢了50倍。爲什麼?這是因爲我們默認爲PersistentArrayMap,其中Clojure不會在定義帶有複雜鍵的小散列映射。

如果我們定義我的地圖這樣反而會發生什麼:

(def my-map 
    (into cljs.core.PersistentHashMap/Empty 
    [[1 2 3] 1 
    [1 2 4] 5 
    [3 4 2] 3 
    [4 5 3] 3 
    [5 2 5] 6 
    [9 2 1] 5 
    [8 3 1] 6])) 

基準然後採取〜170ms,這不是那麼遠了從Clojure的JVM。

所以Clojure實現的優化肯定有很多,我們還沒有做到。不過我想說,對於慣用的Clojure代碼,我認爲我們可以希望在高度優化的JavaScript引擎V8一樣是Clojure的JVM的2-10X ..

+0

謝謝dnolen!通過更多細節查看更新以闡明差異。看起來我現在只需要切換到Chromium;)並且在這裏使用你的建議來使用Hash vs. Array - 很好的瞭解這一點。 –