繁体   English   中英

Clojure性能优化与等效Java

[英]Clojure Performance optimzation vs Equivalent Java

加速此功能的最简单方法是什么? 根据Criterium,java中的等效代码快了近50倍。

我敢打赌,如果我使用java数组并减少拳击量,这将有所帮助,但我想我先发布在这里,看看我是否有任何基本错误,我很容易修复。 注意,我已经为Clojure指出了(double ...),它极大地提高了性能,但仍然没有Java那样。 我还首先使用(双数组...)转换seq而不是在函数内部使用(vec ...),这也提高了性能,但同样,没有像Java那样。

(defn cosine-similarity [ma mb]
  (let [va (vec ma), vb (vec mb)]
    (loop [p (double 0)
           na (double 0)
           nb (double 0)
           i (dec (count va))]
      (if (neg? i)
        (/ p (* (Math/sqrt na) (Math/sqrt nb)))
        (let [a (double (va i))
              b (double (vb i))]
          (recur (+ p (* a b))
                 (+ na (* a a))
                 (+ nb (* b b))
                 (dec i)))))))

请注意,ma和mb都是序列,每个序列包含200个Double。 在Java版本中,它们作为double [] args传递。

使用(double 0)没有直接指定0.0 (双精简版)所得到的性能优势。

如果将mamb作为double-array传递并将args提示为double-array doubles ,不通过vec将它们转换为向量,并使用aget进行元素查找,则会获得明显更好的性能。 这应该使您获得非常接近Java代码性能的东西。

如果将双精度数组用作args函数,则无需在let块内进行double调用。

最终结果应如下所示:

(defn cosine-similarity [^doubles ma ^doubles mb]
  (loop [p 0.0
         na 0.0
         nb 0.0
         i (dec (count va))]
    (if (neg? i)
      (/ p (* (Math/sqrt na) (Math/sqrt nb)))
      (let [a (aget va i)
            b (aget vb i)]
        (recur (+ p (* a b))
               (+ na (* a a))
               (+ nb (* b b))
               (dec i))))))

你尝试过添加吗?

(set! *unchecked-math* true)

由于您知道范围,因此可以使用它来获得额外的速度。

编辑:@noisesmith是正确的,双数组输入输入产生巨大的不同。

Edit2:Alex Miller发表评论后获得了快速的结果。

(set! *unchecked-math* true)

(defn ^double cosine-similarity
  [^doubles va ^doubles vb] 
    (loop [p 0.0
    na 0.0
    nb 0.0
    i  (dec (alength va))]
  (if (< i 0)
    (/ p (* (Math/sqrt na) (Math/sqrt nb)))
    (let [a  (aget va i)
          b  (aget vb i)]
       (recur (+ p (* a b))
         (+ na (* a a))
         (+ nb (* b b))
         (dec i))))))

 (defn rand-double-arr [n m]
   (double-array
     (take n (repeatedly #(rand m)))))

 (def ma (rand-double-arr 200 10000))
 (def mb (rand-double-arr 200 10000))

 ; using do times
 (dotimes [_ 30] (time (cosine-similarity ma mb)))
 ; ...
 ; "Elapsed time: 0.003537 msecs"

 ; using criterium: [criterium "0.4.3"]
 (use 'criterium.core)
 (quick-bench (cosine-similarity ma mb))
 ; 
 ; Execution time mean           : 2.072280 µs
 ; Execution time std-deviation  : 214.653997 ns
 ; Execution time lower quantile : 1.765412 µs ( 2.5%)
 ; Execution time upper quantile : 2.284536 µs (97.5%)
                   Overhead used : 6.128119 ns

第一个版本在500〜1000毫秒范围内...

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM