为什么在aloth基准测试中,clojure比scala更糟糕

时间:2010-11-10 19:42:16

标签: scala clojure performance

参见http://shootout.alioth.debian.org/u32q/compare.php?lang=clojure Clojure比java -server慢得多,而scala不是。

是什么给出了?

参考:On Performance and Java Interoperability: Clojure vs. Scala

6 个答案:

答案 0 :(得分:11)

您可以用任何语言编写快速或慢速代码: - )

基于对某些Clojure代码的快速检查,我想说性能差异的主要原因是Clojure基准代码尚未完全优化以使用最快的语言功能。

例如,Clojure中的以下功能都非常酷且对于开发方便有用,但会产生一些运行时性能开销:

  • 懒惰的序列和列表
  • 使用反射的动态Java互操作性
  • 运行时函数组合/第一类函数
  • Multimethods / dynamic dispatch
  • 使用eval或REPL进行动态编译
  • BigInteger算术

如果您想要绝对的最高性能(以一些额外的复杂性为代价),您可能希望重写代码以避免这些并使用以下内容:

  • 静态类型提示(避免反射)
  • 瞬变
  • 宏(用于编译时代码操作)
  • 协议
  • Java基元和数组
  • 循环/重复迭代

通过明智地使用上述内容,我发现在Clojure 1.2+中通常可以非常接近Java性能,例如:考虑以下代码来做一百万次添加:

未经优化的Clojure 使用惰性序列和大间隔算术。它很好而且功能齐全,但速度不是很快:

(reduce 
  (fn [acc val] (unchecked-int (unchecked-add (int acc) (int val)))) 
  (range 0 1000000))

=> "Elapsed time: 65.201243 msecs"

优化Clojure ,使用原始算法和循环/重复:

(loop [acc (int 0) i (int 0)] 
  (if (>= i (int 1000000)) 
    acc 
    (recur (unchecked-add acc i) (unchecked-inc i)) ))

=> "Elapsed time: 0.691474 msecs"

Java 代码,一个非常标准的迭代循环:

public static int addMillion() {
    int result=0;
    for (int i=0; i<1000000; i++) {
        result+=i;
    }
    return result;
}

=> "Elapsed time: 0.692081 msecs"

P.S。我在Clojure代码中使用了unchecked-add而不是+,以便它匹配Java的整数溢出行为。

答案 1 :(得分:4)

Clojure是一种动态语言,它必须进行一系列额外的运行时检查。

编辑,现在处于一种不那么轻浮的心情:不考虑基准测试的实际Clojure实现,性能差异可能也可以归结为惯用的Clojure代码避开可变状态,并且,在其他条件相同的情况下,使用可变状态的算法通常胜过那些不可变状态的算法。

给定程序员是否能够编写使用可变状态正确的代码是一个不同的问题,当然纯功能代码的声明性质意味着理论上可以进行大量优化,理论上至少。

答案 2 :(得分:3)

部分原因在于测试本身,即您必须编写代码(无论使用何种语言)来执行完全与Java版本相同的实现步骤。哦,你有一种不同的,可能更快的方式来用你的语言做 X 吗?太糟糕了。

当测试的基础是循环和数组绑定以及需要多个浮动代码块的一般命令式样式时,您将获得无意义的数字。

答案 3 :(得分:2)

写一些更快的版本看起来可能很有趣......

答案 4 :(得分:1)

许多基准都比较慢,因为直到最近,它需要更多的工作和专业知识才能从Clojure中获得良好的性能。这些基准目标主要是1.2。

Clojure 1.3有相当多的改进,使得编写高性能代码变得更加简单。即使如此,社区中的许多人都不熟悉提高Clojure代码的性能 - 所以当人们提交更好的版本时,这将是一个渐进的过程。

答案 5 :(得分:-1)

Scala功能通常一点一点地引入,并且在大多数情况下指定相应的Java代码。这将Scala转换为Java的演变,考虑到新功能和性能之间的平衡。

另一方面,Clojure的设计采用了非常不同的编程方法,并具有与Java互操作的功能。但是,两种语言之间的阻抗不匹配(以及JVM为Java做好准备)可能会使Clojure慢一点。对于某些问题,Clojure可能更快(例如使用不可变集合),但可能不适用于大多数应用程序。