一尘不染

NodeJ比Clojure快吗?

node.js

我刚刚开始学习Clojure。我注意到的第一件事是没有循环。可以,我可以重复。因此,让我们看一下这个函数(来自Practical Clojure):

(defn add-up
  "Adds up numbers from 1 to n"
  ([n] (add-up n 0 0))
  ([n i sum] 
    (if (< n i)
      sum
      (recur n (+ 1 i) (+ i sum)))))

为了在Javascript中实现相同的功能,我们使用如下循环:

function addup (n) {
  var sum = 0;
  for(var i = n; i > 0; i--) {
    sum += i;
  }
  return sum;
}

计时后,结果如下所示:

input size: 10,000,000
clojure: 818 ms
nodejs: 160 ms

input size: 55,000,000
clojure: 4051 ms
nodejs: 754 ms

input size: 100,000,000
clojure: 7390 ms
nodejs: 1351 ms

然后,我继续尝试经典的fib(在阅读了此文章之后):

在Clojure中:

(defn fib
  "Fib"
  [n]
  (if (<= n 1) 1
      (+ (fib (- n 1)) (fib (- n 2)))))

在js中:

function fib (n) {
  if (n <= 1) return 1;
  return fib(n-1) + fib(n-2);
}

再次,性能有很大的不同。

fib of 39
clojure: 9092 ms
nodejs: 3484 ms

fib of 40
clojure: 14728 ms
nodejs: 5615 ms

fib of 41
clojure: 23611 ms
nodejs: 9079 ms

注意我在clojure中使用(时间(fib 40)),因此它忽略了JVM的启动时间。这些都是在MacBook Air(1.86
GHz英特尔酷睿2双核)上运行的。

那么,是什么导致Clojure在这里变慢?为什么人们会说“ Clojure快速”?

在此先感谢您,请不要发火焰。


阅读 220

收藏
2020-07-07

共1个答案

一尘不染

(set! *unchecked-math* true)

(defn add-up ^long [^long n]
  (loop [n n i 0 sum 0]
    (if (< n i)
      sum
      (recur n (inc i) (+ i sum)))))

(defn fib ^long [^long n]
  (if (<= n 1) 1
      (+ (fib (dec n)) (fib (- n 2)))))

(comment
  ;; ~130ms
  (dotimes [_ 10]
    (time
     (add-up 1e8)))

  ;; ~1180ms
  (dotimes [_ 10]
    (time
     (fib 41)))
  )

来自2.66ghz i7 Macbook Pro OS X 10.7 JDK 7 64bit的所有数字

如您所见,Node.js被删除了。这与1.3.0 alphas一起使用,但是如果您知道自己在做什么,则可以在1.2.0中实现相同的目的。

在我的机器上,用于添加1e8的Node.js 0.4.8约为990ms,fib 41约为7600ms。

            Node.js  | Clojure
                     |
 add-up       990ms  |   130ms
                     |
 fib(41)     7600ms  |  1180ms
2020-07-07