简体   繁体   English

为什么这个Clojure程序这么慢?如何让它快速运行?

[英]Why is this Clojure program so slow? How to make it run fast?

Here it is clearly explained how to optimize a Clojure program dealing with primitive values: use type annotations and unchecked math, and it will run fast: 这里清楚地解释了如何优化处理原始值的Clojure程序:使用类型注释和未经检查的数学,它将快速运行:

(set! *unchecked-math* true)

(defn add-up ^long [^long n]
  (loop [n n i 0 sum 0]
    (if (< n i)
      sum
      (recur n (inc i) (+ i sum)))))

So, just out of curiosity, I've tried it in lein repl and, to my surprise, found this code running ~20 times slower that expected (Clojure 1.6.0 on Oracle JDK 1.8.0_11 x64): 所以,出于好奇,我已经在lein repl尝试过了,令我惊讶的是,发现这段代码运行速度比预期的慢20倍(Oracle JDK 1.8.0_11 x64上的Clojure 1.6.0):

user=> (time (add-up 1e8))
"Elapsed time: 2719.188432 msecs"
5000000050000000

Equivalent code in Scala 2.10.4 (same JVM) runs in ~90ms: Scala 2.10.4(相同的JVM)中的等效代码在~90ms内运行:

def addup(n: Long) = { 
  @annotation.tailrec def sum(s: Long, i: Long): Long = 
    if (i == 0) s else sum(s + i, i - 1)
  sum(0, n)
}

So, what am I missing in the Clojure code sample? 那么,我在Clojure代码示例中缺少什么? Why is it so slow (should theoretically be roughly the same speed)? 为什么它这么慢(理论上应该大致相同的速度)?

Benchmarking with lein repl is generally a bad idea as it specifically sets non-server JVM settings. 使用lein repl基准测试通常是一个坏主意,因为它专门设置了非服务器JVM设置。 Using the Clojure JAR directly I see ~40ms on a 3.5ghz i7 iMac running JDK 8 under OS X 10.9. 直接使用Clojure JAR,在OS X 10.9下运行JDK 8的3.5ghz i7 iMac上看到~40ms。

Further to @dnolen's answer , a few observations: @ dnolen的回答 ,一些观察结果:

Though it turns out to make no real difference, we should make the Clojure function the same shape as the Scala one. 虽然事实证明没有真正的区别,但我们应该让Clojure函数与Scala函数的形状相同。 In

(defn add-up ^long [^long n]
  (loop [n n i 0 sum 0]
    (if (< n i)
      sum
      (recur n (inc i) (+ i sum)))))
  • n is not changed by the recur , so need not be bound in the loop . n不会被recur改变,所以不需要在loop绑定。
  • The two remaining arguments are in the opposite order to the Scala function. 其余两个参数与Scala函数的顺序相反。
  • It runs up the numbers, whereas the Scala runs down. 它运行数字,而Scala运行。

Mending these inconsistencies, we get 修补这些不一致之处,我们得到了

defn add-up [^long n]
  (loop [sum 0, i n]
    (if (zero? i)
      sum
      (recur (+ sum i) (dec i)))))

(The Scala type system ensures that the argument n is converted to a Long on call. As I understand it (please correct me if I'm wrong), the Clojure ^long type hint promises to treat a Long argument well, but does not promise to convert a Double like 1e8 to a Long . But I got very inconsistent results when I made the corresponding changes.) (Scala类型系统确保参数n在调用时转换为Long 。据我所知(如果我错了请纠正我),Clojure ^long类型提示承诺很好地处理Long参数,但不承诺将像1e8这样的Double转换为Long 。但是当我做出相应的更改时,我的结果非常不一致。)

On my laptop, the above gives 在我的笔记本电脑上,上面给出了

(time (add-up 100000000))
"Elapsed time: 103.636782 msecs"
5000000050000000

If you remove the type hint 如果删除类型提示

(defn add-up [n]
  ...
  )

... the elapsed time multiplies by about twenty: ...经过的时间乘以大约二十:

(time (add-up 100000000))
"Elapsed time: 2374.399915 msecs"
5000000050000000
  • This has more effect than removing unchecked math, which roughly triples the elapsed time. 这比删除未经检查的数学更有效,大约三倍于经过的时间。
  • Type hinting the return type has no discernible effect. 类型提示返回类型没有明显的效果。

All this on Clojure 1.5.0 on OpenJDK Java 7. 所有这些都在OpenJDK Java 7上的Clojure 1.5.0上。

On a three year-old mac book, I get the following: 在一本三年前的mac书上,我得到以下内容:

(time (add-up 1e8))
 "Elapsed time: 68.536 msecs"

and

(time (add-up 1e9))
 "Elapsed time: 771.157 msecs"
  => 500000000500000000

What would be the version of Lein you are using, can you check the clojure Version with: 您正在使用的Lein版本是什么,您可以查看clojure版本:

(clojure-version)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么这个Clojure代码与Java中的替代代码相比如此之慢? - Why is this Clojure code so slow compared to the alternative in Java? 为什么执行SQL查询时我的静态API如此慢? 但是当我只是运行查询时它很快 - Why my restful api is so slow while execute my SQL query? but it fast when i just run the query 为什么快速反平方根在Java上如此奇怪和缓慢? - Why is fast inverse square root so odd and slow on Java? 当我单击开始(框架中的按钮)并减慢它以使循环不快时如何启动我的程序? - How to start my program when I click start (button in frame) and slow it down so the loop isn't to fast? 为什么我的排序程序这么慢? (Java中的基数/存储桶排序) - Why is my sorting program so slow? (radix/bucket sort in java) 为什么 Java HTTP 请求这么慢(与 Python 相比),我怎样才能让它们更快? - Why are Java HTTP requests so slow (in comparison to Python), and how can I make them faster? 为什么杰克逊这么慢? - Why Jackson is so slow? 为什么ReversedLinesFileReader这么慢? - Why is ReversedLinesFileReader so slow? 为什么这个算法这么慢? - why is this algorithm so slow? 如何使用户结束此程序? - How to Make it so that the User ends this program?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM