如何让这个clojure代码运行得更快?

chu*_*nsj 1 performance clojure

我有一个在Lisp(SBCL)中实现的版本,在0.001秒内运行12个样本.然而,这个版本(在clojure中)需要超过1.1秒.我应该怎么做才能让这个代码像原始的Lisp版本一样快速运行?

为了确保,我的数字不包括启动repl和其他人的时间.并且是从sbcl和clojure的时间函数.(是的,我的笔记本电脑是相当旧的原子为基础的)

而且这个应用程序将用于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))))
Run Code Online (Sandbox Code Playgroud)

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

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

Mic*_*zyk 6

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

原因是JVM上的代码开始以解释模式运行,然后最终由JIT编译器编译; 它是JIT编译之后的稳态行为,您希望在分析阶段进行基准测试而不是行为.然而,这是非常棘手的,因为JIT编译器可以在无法操作的地方优化无操作,因此您需要确保您的代码导致无法优化的副作用,但是您仍然需要运行它在循环中获得有意义的结果等 - 快速和肮脏的解决方案只是不削减它.(请参阅Elliptic Group,Inc.Java基准测试文章,该文章也与Criterium的README相关联,以便对所涉及的问题进行扩展讨论.)

循环在长度为1000的向量中列出的两个样本,在我的机器上的Criterium基准测试中得到~327μs的时间:

(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
Run Code Online (Sandbox Code Playgroud)

一个非常好的基准实际上会涉及一个有趣的数据集(所有不同的样本,最好来自现实世界).