我有一张简单的地图:
(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,或者大约700倍。虽然Clojure比ClojureScript更快并不出人意料,但我很困惑为什么ClojureScript会慢得多。
关于如何在ClojureScript中以高效且可读的方式制作简单的多值查找地图的任何想法?我知道做一堆if
而不是使用矢量键解决方案肯定会更快,但我正在寻找一些更具可读性/可维护性的东西。
只是为了更新更多信息。以上是在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的速度仍然比Clojure快13倍,但这比之前要好得多。另请注意,我是直接在浏览器repl中运行它。
答案 0 :(得分:7)
在我的机器上使用高级编译运行您的确切示例需要大约14毫秒的1.7ghz Macbook Air运行一个从源代码构建的相对较新的v8。
为了确保我们对我们认为我们的基准测试进行基准测试,最好写下这样的内容:
(let [v [1 2 8]]
(dotimes [_ 5]
(time
(dotimes [_ 500000]
(get my-map v)))))
在我的机器上,Clojure JVM在机器上需要大约70ms。 ClojureScript在大约3600ms左右运行,因此大约慢50倍。为什么?这是因为我们默认使用PersistentArrayMap,当使用复杂键定义小型哈希映射时,Clojure不会这样做。
如果我们这样定义my-map会发生什么:
(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]))
基准测试需要大约170毫秒,离Clojure JVM不远。
所以Clojure实现了很多优化,我们尚未实现这些优化。我仍然会说,对于惯用的Clojure代码,我认为在V8等高度优化的JavaScript引擎上我们所希望的最好是Clojure JVM的2-10倍。