Clojure记录方法的差异

时间:2014-08-17 09:01:33

标签: performance clojure record

好的,标题并不是我想要的,但我必须在记录的成员函数访问速度中找到一个有趣的东西。我将通过此REPL会话进行说明:

==> (defprotocol Add (add [_]))
Add
==> (defrecord R [x y] Add (add [_] (+ x y)))
=.R
==> (let [r (->R 1 2)] (time (dotimes [_ 100000] (add r)))) ; Pure functional style
"Elapsed time: 19.613694 msecs"
nil
==> (let [r (->R 1 2)] (time (dotimes [_ 100000] (.add r)))) ; Functional creation, but with method call
"Elapsed time: 477.29611 msecs"
nil
==> (let [r (R. 1 2)] (time (dotimes [_ 100000] (.add r)))) ; Java-style
"Elapsed time: 10.051506 msecs"
nil
==> (let [r (R. 1 2)] (time (dotimes [_ 100000] (add r)))) ; Java-style creation with functional call
"Elapsed time: 18.726801 msecs"
nil

我无法真正看出这些差异的原因,所以我要求你这样做。

1 个答案:

答案 0 :(得分:5)

第二次调用的问题是Clojure编译器无法在编译时确定r变量的类型,因此强制使用反射。

要避免它,您应该添加type hint

(let [^user.R r (->R 1 2)] (time (dotimes [_ 100000] (.add r))))

或只是

(let [^R r (->R 1 2)] (time (dotimes [_ 100000] (.add r))))

它和Java风格的方法调用一样快。


如果您想在代码中轻松诊断此类问题,请将*warn-on-reflection*标志设置为true:

(set! *warn-on-reflection* true)

或将其添加到:global-vars文件中的project.clj部分:

:global-vars {*warn-on-reflection* true}

因此,正如您所看到的,没有反射方法调用比函数调用快一点。但反射可能会使方法调用变得非常缓慢。

相关问题