2013-11-24 162 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打印它所花費的時間。