4

我想我会构建一个愚蠢的非尾递归版本的乘法函数,看看它与正确的 TCO 相比如何。但是我注意到,在 REPL(我使用java -cp <classpath> clojure.main配置为的Emacs inferior-lisp)和从命令行调用程序时,显然正在发生某种优化/记忆。事实上,结果在 REPL 中更为明显。

(defn mult-silly [n m]
  (if (> n 0)
    (+ m (mult-silly (dec n) m))
    0))

(dotimes [_ 5]
  (println (time (mult-silly 5000 4)))) 

以上在 REPL 上产生:

user=> #'user/mult-silly
user=> "Elapsed time: 10.697919 ms"
20000
"Elapsed time: 3.069106 ms"
20000
"Elapsed time: 2.301474 ms"
20000
"Elapsed time: 1.285696 ms"
20000
"Elapsed time: 0.554158毫秒"
20000

知道为什么我会看到这个吗?

4

1 回答 1

4

正如@MariusDanila 在他的评论中指出的那样,这是由于 JIT 的作用。

要验证这一点,您可以使用该选项运行 java -Xint,这会导致它以仅解释模式运行,因此不会编译为本机代码(当然也不会对本机代码进行任何优化)。

所以这就是我正常运行java的内容:

"Elapsed time: 4.175 msecs"
20000
"Elapsed time: 2.548 msecs"
20000
"Elapsed time: 7.746 msecs"
20000
"Elapsed time: 1.919 msecs"
20000
"Elapsed time: 1.72 msecs"
20000

请注意,这里的时间实际上增加了第三次运行。我猜这是因为编译同时发生。鉴于-Xint

"Elapsed time: 31.463 msecs"
20000
"Elapsed time: 30.844 msecs"
20000
"Elapsed time: 30.643 msecs"
20000
"Elapsed time: 29.972 msecs"
20000
"Elapsed time: 30.617 msecs"
20000

正如您在第二种情况下看到的那样,没有加速。

这就是为什么微基准测试的规则 1始终从您的测量中排除预热时间。

于 2013-09-09T15:37:58.030 回答