我有一个ClojureScript程序,主要对集合执行数学计算。它是用惯用的、与主机无关的Clojure开发的,因此很容易对其进行基准测试。令我惊讶的是(与Which is faster, Clojure or ClojureScript (and why)?的答案相反),ClojureScript中相同的代码运行速度比它的Clojure等效代码慢5到10倍。
这就是我所做的。我在http://clojurescript.net/上打开了一个http://clojurescript.net/和一个浏览器服务器。然后,我在两个REPL中尝试了这些片段。
(time (dotimes [x 1000000] (+ 2 8)))
(let [coll (list 1 2 3)] (time (dotimes [x 1000000] (first coll))))
然后我在浏览器里打开了一个javascript控制台并编写了一个极简的基准函数,
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:
(defn multiply [] (* 42 1.2))
然后在javascript控制台中尝试本地javascript乘法及其clojurescript变体,
benchmark(1000000, cljs.user.multiply);
benchmark(1000000, function(){ 42 * 1.2 });
我发现的
现在我的问题是,如何提高我的ClojureScript程序的性能?
到目前为止,我已经考虑过一些方法
(aget js/v 0)
一起使用javascript数组发布于 2013-05-14 19:59:00
JavaScript有显式返回,因此
function () { 42 * 1.2 }
什么也不做,你会想要基准测试
function () { return 42 * 1.2 }
而不是。这恰好是ClojureScript版本编译的内容,因此不会有任何区别(在ClojureScript中,非高阶用法中的基本算术函数被内联为基于常规运算符的JavaScript表达式)。
现在,Clojure在这一点上绝对比ClojureScript快。部分原因是Clojure仍然比ClojureScript更仔细地调优,尽管ClojureScript在这个部门正在以相当大的速度改进。另一部分是Clojure有一个更成熟的JIT来利用(现代的JS引擎,特别是V8,非常棒,但还没有达到热点级)。
然而,衡量这种差异的程度有点棘手;JIT涉及的事实意味着,一个没有任何副作用的循环(比如问题中的那个)很可能会被优化,甚至在第一次运行时也是如此(通过使用HotSpot和V8使用的栈上替换--我认为--我必须检查一下才能确定)。所以,最好做一些基准测试,比如
(def arr (long-array 1))
;;; benchmark this
(dotimes [_ 1000000]
(aset (longs arr) 0 (inc (aget (longs arr) 0))))
(longs
调用以避免在Clojure中进行反射;也可以使用^longs
提示)。
最后,对于某些对性能特别敏感的代码,无论是Clojure还是ClojureScript,最好使用本机数组等等。幸运的是,这样做没有问题:在ClojureScript方面,您有array
、js-obj
、aget
、aset
、make-array
,您可以在deftype
中的字段中使用:mutable
元数据,以便能够在方法体中对它们进行set!
等等。
发布于 2013-05-14 20:35:10
ClojureScript数学是JavaScript数学。是的,如果性能非常关键,请使用JavaScript数组和提供的低级操作符,这些操作保证在可能的情况下产生最佳代码(即不使用更高的顺序)。ClojureScript持久化数据结构采用数组变异、算术、位旋转等方式。
我有一个关于高效的ClojureScript - stl/spectral/demo.cljs的小例子,您可能会发现它作为指南很有用。
https://stackoverflow.com/questions/16548136
复制相似问题