请看http://shootout.alioth.debian.org/u32q/compare.php?lang=clojure,Clojure比Java -server慢得多,而Scala则不是。
为什么会这样呢?
请看http://shootout.alioth.debian.org/u32q/compare.php?lang=clojure,Clojure比Java -server慢得多,而Scala则不是。
为什么会这样呢?
任何语言都可以编写快速或慢速的代码 :-)
根据对一些Clojure代码的快速检查,我认为性能差异的主要原因是Clojure基准测试代码尚未完全优化以使用最快的语言功能。
例如,Clojure中以下功能非常酷且有用于开发方便,但会产生一些运行时性能开销:
如果您想获得绝对最大的性能(以一些额外的复杂性为代价),则应重写代码以避免这些问题,并使用以下内容:
通过巧妙地使用上述内容,我发现在Clojure 1.2+中通常可以获得非常接近Java性能的水平,例如考虑以下代码以执行一百万次加法:
未经优化的Clojure使用懒惰序列和BigInteger算术。它很好用,但不是特别快:
(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 的整数溢出行为。
Clojure是一种动态语言,它需要进行大量的运行时检查。
编辑,现在的情绪不那么轻浮:没有查看实际的Clojure基准测试实现,性能差异可能也可以归因于典型的Clojure代码避免使用可变状态,其他条件相同,使用可变状态的算法通常优于不使用可变状态的算法。
一个程序员能否编写正确使用可变状态的代码是另一个问题,当然纯函数式代码的声明性质意味着很多优化在理论上都成为可能。
部分原因是由于测试本身,即您必须编写代码(无论使用哪种语言),以执行与Java版本完全相同的实现步骤。哦,您有一种不同、可能更快的方法来执行X吗?太糟糕了。
当测试的基础是循环和数组操作,以及需要多个浮动的代码块的一般命令式样式时,您将得到毫无意义的数字。
许多基准测试较慢,因为直到最近,要想从Clojure中获得良好的性能需要更多的工作和专业知识。这些基准测试主要针对1.2版本。
Clojure 1.3有很多改进,使编写高性能代码变得更加简单。即便如此,社区中熟悉Clojure代码性能优化的人并不是很多,因此随着人们提交更好的版本,这将是一个逐渐的过程。
Scala的特性通常是逐步引入的,在大多数情况下会指定相应的Java代码。这使得Scala成为Java的一种进化,考虑到新功能和性能之间的平衡。
另一方面,Clojure则是以非常不同的编程方法为设计基础,并具有与Java进行交互的特性。然而,两种语言之间存在的阻抗失配(以及JVM是为Java准备的)可能会使Clojure稍微慢一些。对于某些问题,Clojure可能更快(例如使用不可变集合),但对于大多数应用程序可能并非如此。