mik*_*era 11

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

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

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

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

如果你想要绝对的最大性能(以一些额外的复杂性为代价),你会想要重写代码以避免这些并使用如下的东西:

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

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

未经优化的Clojure使用惰性序列和biginterger算法.这很好用,但功能不是很快:

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

=> "Elapsed time: 65.201243 msecs"
Run Code Online (Sandbox Code Playgroud)

使用原始算法和循环/重复进行优化的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"
Run Code Online (Sandbox Code Playgroud)

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

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

=> "Elapsed time: 0.692081 msecs"
Run Code Online (Sandbox Code Playgroud)

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

  • 您可以通过贡献程序来证明它特别"可以在Clojure 1.2+中非常接近Java性能";-) (10认同)
  • @igouy - 废话,我已经演示了如何使Clojure与Java速度相匹配的技术,这就是答案的全部目的.请注意,我的"业务要求"明确表示要增加一百万,所以结果无关紧要. (4认同)
  • 目前在优化基准测试方面存在一些缄默.Clojure 1.3处于alpha阶段,带来了大量的性能提升,并为快速代码删除了大量注释.大多数人认为在优化基准测试之前等待1.3稳定更好. (4认同)