Clojure性能:REPL与uberjar [英] Clojure performance: REPL versus uberjar

查看:123
本文介绍了Clojure性能:REPL与uberjar的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做一些实时图形渲染,并试图对每个像素每帧进行多次计算。然后我很快注意到这是非常缓慢,并开始在非常基础:我可以循环所有的像素多快?



我发现dotimes相当快,但是当我在REPL中执行此操作非常慢:

  user => 
已用时间:409.177477 msecs
已用时间:417.755502 msecs
已用时间(dotimes [_ 10](time(dotimes [_ 1e7](+ 11)))时间:418.939182 msecs
已用时间:420.131575 msecs
已用时间:419.83529 msecs
已用时间:417.612003 msecs
已用时间:420.749229 msecs
已用时间:418.918554 msecs
已用时间:414.403957 msecs
已用时间:417.729624 msecs
nil
user =>

然后我把它放到Leiningen项目中。当我做一个lein run它是同样慢。但是当我创建uberjar并使用java命令运行它时,速度会快很多:

 %java -jar target / looping- 0.1.0-SNAPSHOT-standalone.jar 
已用时间:122.006758 msecs
已用时间:3.667653 msecs
已用时间:3.60515 msecs
4.008436 msecs
经过时间:3.961558 msecs
经过时间:3.60212 msecs
经过时间:3.592532 msecs
经过时间:4.573949 msecs
已用时间:3.959568 msecs
已用时间:3.607495 msecs

第一次跑步还是很慢。有什么不同?在这两种情况下代码都是编译的,没有解释Clojure,对吧?是JIT,一些优化还是为REPL设置了一些特殊的JVM选项?



感谢任何想法。

:jvm-opts ^:replace [] 添加到你的 project.clj






除此之外,虽然下面的内容没有添加任何东西来解释REPL之间的时间差异和überjar,我想我会评论基准,如果你关心准确的结果:



时间不是一个良好的基准工具,无论是 dotimes 。 (No dotimes - JIT编译器不会启动;使用 dotimes - 它可能会,决定循环的主体是一个noop并将其完全优化。)



Hugo Duncan的 Criterium 是一种可靠的Clojure解决方案,可以处理JIT预热,以不会优化的方式循环,并对结果进行统计处理。一个简单的Criterium基准可能如下所示:

 (require'[criterionium.core:as c])

(def v [0 1 2])

(c / bench(nth v 0))

(这测量访问Var中保存的短向量的初始元素的时间,我希望(+ 1 1)最终被编译为常量,因此可能没有任何剩余的基准。)


I wanted to do some real-time graphics rendering and was trying to do multiple calculations per pixel per frame. I then quickly noticed that this was very slow and started at the very base: how fast can I loop over all the pixels?

I found dotimes reasonably fast, but when I do this in a REPL it is awfully slow:

user=> (dotimes [_ 10] (time (dotimes [_ 1e7] (+ 1 1))))
"Elapsed time: 409.177477 msecs"
"Elapsed time: 417.755502 msecs"
"Elapsed time: 418.939182 msecs"
"Elapsed time: 420.131575 msecs"
"Elapsed time: 419.83529 msecs"
"Elapsed time: 417.612003 msecs"
"Elapsed time: 420.749229 msecs"
"Elapsed time: 418.918554 msecs"
"Elapsed time: 414.403957 msecs"
"Elapsed time: 417.729624 msecs"
nil
user=>

Then I put this into a Leiningen project. When I do a "lein run" it is just as slow. But when I create the uberjar and run it with the java command it's a lot faster:

% java -jar target/looping-0.1.0-SNAPSHOT-standalone.jar 
"Elapsed time: 122.006758 msecs"
"Elapsed time: 3.667653 msecs"
"Elapsed time: 3.60515 msecs"
"Elapsed time: 4.008436 msecs"
"Elapsed time: 3.961558 msecs"
"Elapsed time: 3.60212 msecs"
"Elapsed time: 3.592532 msecs"
"Elapsed time: 4.573949 msecs"
"Elapsed time: 3.959568 msecs"
"Elapsed time: 3.607495 msecs"

Although the first run is still a lot slower. What is the difference? In both cases the code is compiled, there is no interpreted Clojure, right? Is it JIT, some optimizations or some special JVM options that are set for the REPL?

Thanks for any ideas.

解决方案

Leiningen runs the JVM with certain default options that improve startup time, but impair runtime performance. So, you might want to check again with :jvm-opts ^:replace [] added to your project.clj.


Apart from this, while the below doesn't add anything in the way of explaining the timing discrepancy between the REPL and the überjar, I thought I'd comment on benchmarking in case you care about accurate results:

time is not a good tool for benchmarking, whether with dotimes or not. (No dotimes -- the JIT compiler will not kick in; with dotimes -- it probably will, but may well decide that the body of the loop is a noop and optimize it away completely.)

Hugo Duncan's Criterium is the robust Clojure solution that takes care of JIT warm-up, looping in a way which will not be optimized away and statistical processing of the results. A simple Criterium benchmark might look like this:

(require '[criterium.core :as c])

(def v [0 1 2])

(c/bench (nth v 0))

(This measures the time to access the initial element of a short vector held in a Var. I'd expect (+ 1 1) eventually to be compiled to a constant, so there may be nothing left to benchmark.)

这篇关于Clojure性能:REPL与uberjar的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆