我在Clojure中找到了这个代码来筛选出第一个 n 素数:
(defn sieve [n]
(let [n (int n)]
"Returns a list of all primes from 2 to n"
(let [root (int (Math/round (Math/floor (Math/sqrt n))))]
(loop [i (int 3)
a (int-array n)
result (list 2)]
(if (>= i n)
(reverse result)
(recur (+ i (int 2))
(if (< i root)
(loop [arr a
inc (+ i i)
j (* i i)]
(if (>= j n)
arr
(recur (do (aset arr j (int 1)) arr)
inc
(+ j inc))))
a)
(if (zero? (aget a i))
(conj result i)
result)))))))
然后我在Scheme中编写了等效(我认为)的代码(我使用mit-scheme)
(define (sieve n)
(let ((root (round (sqrt n)))
(a (make-vector n)))
(define (cross-out t to dt)
(cond ((> t to) 0)
(else
(vector-set! a t #t)
(cross-out (+ t dt) to dt)
)))
(define (iter i result)
(cond ((>= i n) (reverse result))
(else
(if (< i root)
(cross-out (* i i) (- n 1) (+ i i)))
(iter (+ i 2) (if (vector-ref a i)
result
(cons i result))))))
(iter 3 (list 2))))
时间结果如下: 对于Clojure:
(time (reduce + 0 (sieve 5000000)))
"Elapsed time: 168.01169 msecs"
对于mit-scheme:
(time (fold + 0 (sieve 5000000)))
"Elapsed time: 3990 msecs"
有谁能告诉我为什么mit-scheme慢了20多倍?
update :&#34;区别在于iterpreted / compiled模式。编译完mit方案代码后,它的运行速度相当快。 - abo-abo Apr 30 '12 at 15:43&#34;
答案 0 :(得分:15)
与解释型语言相比,Java虚拟机的现代版本具有极佳的性能。大量的工程资源已经进入JVM,特别是热点JIT编译器,高度调整的垃圾收集等等。
我怀疑你看到的差异主要取决于那个。例如,如果查看Are the Java programs faster? ,您可以看到java与ruby的比较,这表明java在其中一个基准测试中的性能优于220倍。
您没有说明运行clojure基准测试的JVM选项。尝试使用-Xint
标志运行java,该标志以纯解释模式运行,看看有什么区别。
此外,您的示例可能太小而无法真正预热JIT编译器。使用更大的示例可能会产生更大的性能差异。
让您了解Hotspot对您有多大帮助。我在我的MBP 2011(四核2.2Ghz)上运行了你的代码,使用带有默认opts(-server hotspot)和解释模式(-Xint)的java 1.6.0_31并看到了很大的差异
; with -server hotspot (best of 10 runs)
>(time (reduce + 0 (sieve 5000000)))
"Elapsed time: 282.322 msecs"
838596693108
; in interpreted mode using -Xint cmdline arg
> (time (reduce + 0 (sieve 5000000)))
"Elapsed time: 3268.823 msecs"
838596693108
答案 1 :(得分:5)
至于比较Scheme和Clojure代码,在Clojure端有一些简化的事情:
代码:
(defn sieve [^long n]
(let [root (int (Math/sqrt n))
a (int-array n)]
(loop [i 3, result (list 2)]
(if (>= i n)
(reverse result)
(do
(when (< i root)
(loop [inc (+ i i), j (* i i)]
(when (>= j n) (aset a j 1) (recur inc (+ j inc)))))
(recur (+ i 2) (if (zero? (aget a i))
(conj result i)
result)))))))