首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何提高ClojureScript性能

如何提高ClojureScript性能
EN

Stack Overflow用户
提问于 2014-02-12 07:11:00
回答 2查看 3.5K关注 0票数 7

我最近开始使用ClojureScript。当我将JavaScript程序重写为ClojureScript时,我担心ClojureScript的性能。

ClojureScript代码

代码语言:javascript
复制
(def NUM 10000)
(def data
  (vec (repeatedly NUM #(hash-map :x (rand) :y (rand)))))

(.time js/console "cljs")
(loop [x 0 y 0 d data]
  (if (empty? d)
    [x y]
    (recur (+ x (:x (first d)))
           (+ y (:y (first d)))
           (rest d))))
(.timeEnd js/console "cljs")

编译的JavaScript代码(优化:空白)

代码语言:javascript
复制
benchmark_cljs.benchmark.NUM = 1E4;
benchmark_cljs.benchmark.data = cljs.core.vec.call(null, cljs.core.repeatedly.call(null, benchmark_cljs.benchmark.NUM, function() {
  return cljs.core.PersistentHashMap.fromArrays.call(null, [new cljs.core.Keyword(null, "x", "x", 1013904362), new cljs.core.Keyword(null    , "y", "y", 1013904363)], [cljs.core.rand.call(null), cljs.core.rand.call(null)]);
}));
console.time("cljs");
var x_4753 = 0;
var y_4754 = 0;
var d_4755 = benchmark_cljs.benchmark.data;
while (true) {
  if (cljs.core.empty_QMARK_.call(null, d_4755)) {
    new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [x_4753, y_4754], null);
  } else {
    var G__4756 = x_4753 + (new cljs.core.Keyword(null, "x", "x", 1013904362)).cljs$core$IFn$_invoke$arity$1(cljs.core.first.call(null, d    _4755));
    var G__4757 = y_4754 + (new cljs.core.Keyword(null, "y", "y", 1013904363)).cljs$core$IFn$_invoke$arity$1(cljs.core.first.call(null, d    _4755));
    var G__4758 = cljs.core.rest.call(null, d_4755);
    x_4753 = G__4756;
    y_4754 = G__4757;
    d_4755 = G__4758;
    continue;
  }
  break;
}
console.timeEnd("cljs");

JavaScript代码

代码语言:javascript
复制
var NUM = 10000;
var data = [];
for (var i = 0; i < NUM; i++) {
  data[i] = {
    x: Math.random(),
    y: Math.random()
  }
}
console.time('js');
var x = 0;
var y = 0;
for (var i = 0; i < data.length; i++) {
  x += data[i].x;
  y += data[i].y;
}
console.timeEnd('js');

ClojureScript代码和JavaScrpt代码所做的事情是相同的,但是每个进程时间是不同的。

处理时间

代码语言:javascript
复制
ClojureScript(optimizations :whitespace): 30 〜 70ms
ClojureScript(optimizations :advanced): 9 〜 13ms
JavaScript: 0.3ms 〜 0.9ms

请告诉我如何提高ClojureScript的处理时间。

提前谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-02-12 07:28:14

在ClojureScript中使用持久数据结构,在JavaScript中使用可变数组和对象。这两个代码段的性能特征是不同的。

现在,如果性能对您所做的事情非常重要,而持久性并没有带来任何好处,那么您可以只使用来自ClojureScript的数组和对象:

代码语言:javascript
复制
(def NUM 10000)
(def data (array))
(loop [i 0]
  (when (< i NUM)
    (aset data i (js-obj "x" (js/Math.random) "y" (js/Math.random)))
    (recur (inc i))))

(let [lim (alength data)]
  (loop [x 0 y 0 i 0]
    (if (< i lim)
      (recur (+ x (aget data i "x"))
             (+ y (aget data i "y"))
             (inc i))
      (println x y))))

另一方面,如果您确实需要保留所涉及的数据结构的旧版本,您可能不需要制作完整的副本来保存它们,从而赢得您“失去的时间”。

票数 13
EN

Stack Overflow用户

发布于 2014-02-18 06:25:22

你在这里有很多选择,取决于你需要多少性能,你愿意放弃什么。如果你有兴趣的话,我把一些基准放在GitHub上。

通过使用记录和本机字段访问,您可以将原始ClojureScript解决方案的运行时减半:

代码语言:javascript
复制
(defrecord XY [x y])
(def data (mapv (fn [_] (XY. (rand) (rand))) (range NUM))) 

(defn sumXsAndYsWithLoopAndNativeFieldAccess [data]
  (loop [x 0 y 0 data data]
    (if (seq data)
      (let [o (first data)]
        (recur (+ x (.-x o)) (+ y (.-y o)) (rest data)))
      [x y])))

(time (sumXsAndYsWithLoopAndNativeFieldAccess data))

您还可以使用数组作为可变的局部变量,并且获得的解决方案只比本机JavaScript版本慢8倍:

代码语言:javascript
复制
(defn sumsXsAndYsWithDotimesNativeFieldAccessAndMutableLocals [data]
  (let [x (doto (make-array 1)
            (aset 0 0))
        y (doto (make-array 1)
            (aset 0 0))]
    (dotimes [i (count data)]
      (let [o (data i)]
        (aset x 0 (+ (aget x 0) (.-x o)))
        (aset y 0 (+ (aget y 0) (.-y o)))))
    [(aget x 0) (aget y 0)]))

(time (sumsXsAndYsWithDotimesNativeFieldAccessAndMutableLocals data))

此外,您可以将上面的内容与数组结合使用,并实现一个比本机JavaScript版本慢大约3倍的解决方案:

代码语言:javascript
复制
(def data (into-array (mapv #(XY. (rand) (rand)) (range NUM))))

(defn sumsXsAndYsWithDotimesOnArrayNativeFieldAccessAndMutableLocals [data]
  (let [x (doto (make-array 1)
            (aset 0 0))
        y (doto (make-array 1)
            (aset 0 0))]
    (dotimes [i (alength data)]
      (let [o (aget data i)]
        (aset x 0 (+ (aget x 0) (.-x o)))
        (aset y 0 (+ (aget y 0) (.-y o)))))
    [(aget x 0) (aget y 0)]))

(time (sumsXsAndYsWithDotimesOnArrayNativeFieldAccessAndMutableLocals data))

您可能需要查看David的内腔项目。他有一些很好的宏,用于创建和更新本地变量,这些宏使上面的内容看起来并不可笑。

不管怎样,希望这能帮上忙。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21721028

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档