2013-11-24 116 views
1

我有一个版本在Lisp(SBCL)中运行,它在0.001秒内运行12个样本。然而这个版本(在clojure中)需要超过1.1秒。 我应该如何让这段代码运行得和原始Lisp版本一样快?如何让这个clojure代码运行得更快?

为了使它肯定的是,我的数字不包括次启动REPL等。 (是的,我的笔记本电脑基本上是基于原子的)

而这个应用程序是/将在repl中使用,而不是在单个应用程序中编译,所以运行千次基准测试似乎没有意义。

哦,fbars是这样的:[[10.0 10.5 9.8 10.1] [10.1 10.8 10.1 10.7] ...],这是 股票的开盘 - 最高 - 低 - 收盘价。

(defn- build-new-smpl [fmx fmn h l c o] 
    (let [fmax (max fmx h) 
     fmin (min fmn l) 
     fc (/ (+ c fmax fmin) 3.0) 
     fcd (Math/round (* (- fc o) 1000)) 
     frd (Math/round (* (- (* 2.0 c) fmax fmin) 1000))] 
    (if (and (> fcd 0) (> frd 0)) 
     [1 fmax fmin] 
     (if (and (< fcd 0) (< frd 0)) 
     [-1 fmax fmin] 
     [0 fmax fmin])))) 

(defn binary-smpls-using [fbars] 
    (let [fopen (first (first fbars))] 
    (loop [fbars fbars, smpls [], fmax fopen, fmin fopen] 
     (if (> (count fbars) 0) 
     (let [bar (first fbars) 
       [_ h l c _] bar 
       [nsmpl fmx fmn] (build-new-smpl fmax fmin h l c fopen)] 
      (recur (rest fbars) (conj smpls nsmpl) fmx fmn)) 
     smpls)))) 

=========================================== =====

谢谢。我设法让差异1000次迭代为0.5秒(SBCL为1.3秒,Clojure为1.8)。主要因素是我应该创建fbars不懒惰,但作为具体(?)矢量或数组,这解决了我的问题。

回答

6

您需要使用适当的基准测试库;标准的Clojure解决方案是Hugo Duncan的Criterium

的原因是在JVM上的代码开始在解释模式下运行,然后最终得到由JIT编译器编译;这是JIT编译后的稳态行为,您希望在性能分析阶段进行基准测试而不是行为测试。然而,这是非常棘手的,因为JIT编译器会优化无操作的地方,因此您需要确保代码产生的副作用不会被优化,但是您仍然需要运行它在一个循环中获得有意义的结果等 - 快速和肮脏的解决方案不会削减它。 (请参阅Elliptic Group, Inc. Java benchmarking article,也链接到Criterium的自述文件,以深入讨论所涉及的问题。)

骑自行车,你长的矢量列出的两个样本1000个结果中的时序〜327微秒在我的机器上绕圈基准:

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

(def v (vec (take 1000 (cycle [[10.0 10.5 9.8 10.1] [10.1 10.8 10.1 10.7]])))) 

(c/bench (binary-smpls-using v)) 
WARNING: Final GC required 4.480116525558204 % of runtime 
Evaluation count : 184320 in 60 samples of 3072 calls. 
      Execution time mean : 327.171892 µs 
    Execution time std-deviation : 3.129050 µs 
    Execution time lower quantile : 322.731261 µs (2.5%) 
    Execution time upper quantile : 333.117724 µs (97.5%) 
        Overhead used : 1.900032 ns 

Found 1 outliers in 60 samples (1.6667 %) 
    low-severe 1 (1.6667 %) 
Variance from outliers : 1.6389 % Variance is slightly inflated by outliers 

一个非常好的标杆实际上涉及到一个有趣的数据集(所有不同的样品,最好来自现实世界)。

3

当我用1000个样本运行此我得到一个答案在46毫秒,虽然这里有上做出的Clojure代码更快一些常见的技巧:

  • 反过来细想警告:

    (设定! 警告上反射真)

  • 增加类别提示,直到反射警告消失,这不是一个问题在这里

  • 使它成为一个懒惰的序列,所以你不必在RAM中构造巨大的序列,这导致大量的GC开销。 (在某些情况下,这会增加开销,虽然我认为这是这里不错的主意)

  • 在这样的情况下

    看看能为你做的工作(虽然可能被欺骗)

  • 时间创造结果排除了repl打印它所花费的时间。