提高ClojureScript程序的性能

时间:2013-05-14 16:19:32

标签: performance clojure clojurescript

我有一个ClojureScript程序,主要对集合执行数学计算。它是在惯用的,独立于主机的Clojure中开发的,因此很容易对它进行基准测试。令我惊讶的是(与Which is faster, Clojure or ClojureScript (and why)?的答案相反),ClojureScript中的相同代码运行速度比Clojure等同的速度低5-10倍。

这就是我所做的。我在http://clojurescript.net/打开了lein repl和浏览器代表。然后我在两个REPL中尝试了这些片段。

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

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

然后我在浏览器repl上打开了一个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 });

我找到了什么

  • 本机javascript数学与clojure中的数学相媲美
  • ClojureScript比其中任何一个慢5-10倍

现在我的问题是,如何改善ClojureScript程序的性能?

到目前为止,我已经考虑了一些方法

  • 回到幕后使用可变的javascript数组和对象。 (这有可能吗?)
  • 回归使用原生javascript数学运算符。 (这有可能吗?)
  • 使用(aget js/v 0)
  • 明确使用javascript数组
  • 使用不那么雄心勃勃的clojure-for-javascript实现,例如https://github.com/chlorinejs/chlorinehttps://github.com/gozala/wisp它们会生成一个更惯用的javascript,但它们不支持我经常使用的命名空间。< / LI>

2 个答案:

答案 0 :(得分:10)

JavaScript有明确的回报,所以

function () { 42 * 1.2 }

什么都不做;你想要进行基准测试

function () { return 42 * 1.2 }

代替。这恰好是ClojureScript版本编译的内容,因此没有任何区别(在ClojureScript中,非高阶用法中的基本算术函数被内联为常规的基于运算符的JavaScript表达式)。

现在,Clojure在这一点上肯定比ClojureScript更快。部分原因是Clojure仍然比ClojureScript更精心调整,尽管ClojureScript在这个部门的发展速度非常快。另一部分是Clojure有一个更成熟的JIT可以利用(现代的JS引擎,尤其是V8,非常棒,但还不是HotSpot级)。

但差异的大小在某种程度上难以衡量;涉及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方面,你有arrayjs-objagetasetmake-array,你可以在:mutable中的字段上使用deftype元数据,以便能够在方法体等中set!

答案 1 :(得分:7)

ClojureScript math JavaScript数学。是的,如果性能至关重要,请使用JavaScript数组和提供的低级运算符,这些运算符可以保证在可能的情况下生成最佳代码(即没有更高的订单使用率)。 ClojureScript持久性数据结构以这种方式编写:数组变异,算术,比特翻转。

我有一个高效的ClojureScript示例 - http://github.com/swannodette/cljs-stl/blob/master/src/cljs_stl/spectral/demo.cljs,您可能会觉得它很有用。