我是Clojure的新手。在实验中,我编写了函数来计算n!
。我的Clojure代码如下:
(defn factorial
[n]
(reduce * (biginteger 1) (range 1 (inc n))))
然后,我在一个副本中运行以下内容。
(time (factorial 100))
结果是:
"Elapsed time: 0.50832 msecs"
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000N
然后,我在Ruby中创建了一个类似的解决方案:
def factorial(n)
start = Time.now.to_f
(2..n).inject(1) { |p, f| p * f }
finish = Time.now.to_f
time_taken = finish - start
puts "It took: #{(time_taken * 1000)} msecs"
end
我运行的带有irb的factorial(100)
结果是:
It took: 0.06556510925292969 msecs
=> 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
尽管我看到的大多数证据都表明Clojure应该具有更好的性能,但Ruby版本的性能似乎要好得多。我是否有误解或Clojure解决方案中的某些因素会使它变慢?
Miro基准测试经常会产生误导,总的来说,很难正确地进行基准测试。最接近clojure的最简单方法(我发现是标准库(感谢Hugo!)。如果我通过循环简单地从一个丑陋的阶乘计算开始,我将获得约3 ns。
user> (defn loopy-fact [x]
(loop [y x
answer-so-far 1]
(if (pos? y)
(recur (dec y) (*' answer-so-far y))
answer-so-far)))
#'user/loopy-fact
user> (loopy-fact 100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000N
然后让我们对其进行基准测试:
user> (criterium.core/bench #(loopy-fact 100))
WARNING: Final GC required 11.10521514596218 % of runtime
WARNING: Final GC required 1.069604210579865 % of runtime
Evaluation count : 12632130300 in 60 samples of 210535505 calls.
Execution time mean : 2.978360 ns
Execution time std-deviation : 0.116043 ns
Execution time lower quantile : 2.874266 ns ( 2.5%)
Execution time upper quantile : 3.243399 ns (97.5%)
Overhead used : 1.844334 ns
Found 4 outliers in 60 samples (6.6667 %)
low-severe 2 (3.3333 %)
low-mild 2 (3.3333 %)
Variance from outliers : 25.4468 % Variance is moderately inflated by outliers
然后,如果我们使用正常的Clojure样式(带有map和reduce),并且不费吹灰之力,就可以使代码看起来更好。
user> (defn mapy-fact [x]
(reduce *' (range 1 (inc x)))
#'user/mapy-fact
user> (mapy-fact 100)
933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000N
现在,让我们来看看它们之间的比较:
user> (criterium.core/bench #(mapy-fact 100))
Evaluation count : 8674569060 in 60 samples of 144576151 calls.
Execution time mean : 5.208031 ns
Execution time std-deviation : 0.265287 ns
Execution time lower quantile : 5.032058 ns ( 2.5%)
Execution time upper quantile : 5.833466 ns (97.5%)
Overhead used : 1.844334 ns
Found 4 outliers in 60 samples (6.6667 %)
low-severe 1 (1.6667 %)
low-mild 3 (5.0000 %)
Variance from outliers : 36.8585 % Variance is moderately inflated by outliers
它有点慢,但仅慢了2纳秒。
这比在测试中看起来要好得多,因为criterium运行该函数足够的时间,以便JVM的Hotspot编译器可以编译它并内联所有部分。这说明了为什么微基准测试在JVM上可能会产生误导。在这种情况下,您几乎应该确定所有标准。
PS:*'
是“自动提升”乘法运算符,它将根据需要将其类型提升为大整数或大十进制
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句