mac*_*021 4 performance clojure
这是一个简短的Scala程序,它通过生成一组随机数来计算Euler数的差的近似值:
package example
import scala.util.Random
object ApproxE extends App {
def calc = {
var S = 0.0
for {i <- 1 to 100000000} {
var x = 0.0
var t = 0
while (x <= 1.0) {
x += Random.nextDouble
t += 1
}
S += t
}
S / 100000000
}
val st = System.currentTimeMillis()
val e = calc
val ed = System.currentTimeMillis()
println(e)
println(ed - st)
}
Run Code Online (Sandbox Code Playgroud)
在我的笔记本电脑上运行,它在大约7秒内完成计算.
以下是两个等效的Clojure函数.在48秒内返回,在230秒内返回.
在纯Clojure中,是否有可能编写一个性能与Java或Scala中可实现的性能相当的等效程序?
48S:
(defn calc []
(loop [i (int 0)
S (double 0.0)]
(if (= i 100000000)
(/ S 100000000)
(let [rs (repeatedly rand)
ps (reductions + rs)
<=1 #(<= % 1)]
(->> ps
(take-while <=1)
(count)
(inc)
(+ S)
(recur (inc i)))))))
Run Code Online (Sandbox Code Playgroud)
230S:
(defn calc2 []
(with-local-vars [S 0.0]
(dotimes [i 100000000]
(with-local-vars [x (double 0)
t (int 0)]
(while (<= @x 1)
(var-set x (+ @x (rand)))
(var-set t (inc @t)))
(var-set S (+ @S @t))))
(/ @S 100000000)))
Run Code Online (Sandbox Code Playgroud)
两个懒惰的数据结构和本地变量引入造成的开销分配(尽管你仍然可以用VARS快一点通过移动分配的变异x和t圈外),名称解析(在瓦尔的情况下)和方法调用.
Scala代码的单词到单词转换将使用本地绑定(使用let和loop),它们等同于Java的局部变量:
(defn calc-loops []
(loop [i (int 0)
S (double 0.0)]
(if (= i 100000000)
(/ S 100000000)
(recur
(inc i)
(loop [t 0 x 0.0]
(if (<= x 1.0)
(recur (inc t) (+ x (rand)))
(+ S t)))))))
(time (calc)) ;; => "Elapsed time: 56255.692677 msecs"
(time (calc-loops)) ;; => "Elapsed time: 8800.746127 msecs"
Run Code Online (Sandbox Code Playgroud)