Clojure 1.3中的功能性能

end*_*gin 4 performance clojure

我想知道是否有人可以帮助我在Clojure 1.3中使用此代码片段的性能.我正在尝试实现一个简单的函数,它需要两个向量并完成一系列产品.

因此,假设向量是X(大小为10,000个元素)和B(大小为3个元素),并且乘积之和存储在向量Y中,数学上看起来像这样:

Y0 = B0*X2 + B1*X1 + B2*X0

Y1 = B0*X3 + B1*X2 + B2*X1

Y2 = B0*X4 + B1*X3 + B2*X2

等等 ...

对于此示例,Y的大小最终将为9997,对应于(10,000 - 3).我已经设置了接受任何大小的X和B的函数.

这是代码:它基本上(count b)从X一次获取元素,反转它,映射*到B并对结果序列的内容求和以产生Y的元素.

(defn filt [b-vec x-vec]
  (loop [n 0 sig x-vec result []]
    (if (= n (- (count x-vec) (count b-vec)))
      result
      (recur (inc n) (rest sig) (conj result (->> sig
                                                  (take (count b-vec))
                                                  (reverse)
                                                  (map * b-vec)
                                                  (apply +)))))))
Run Code Online (Sandbox Code Playgroud)

在让X (vec (range 1 10001))和B成为时[1 2 3],此功能大约需要6秒才能运行.我希望有人可以建议改进运行时间,无论是算法,还是我可能滥用的语言细节.

谢谢!

PS我已经完成(set! *warn-on-reflection* true)但没有得到任何反射警告信息.

Ank*_*kur 7

你不必多次使用计数.下面的代码只计算一次计数

(defn filt [b-vec x-vec]
  (let [bc (count b-vec) xc (count x-vec)]
    (loop [n 0 sig x-vec result []]
        (if (= n (- xc bc))
          result
          (recur (inc n) (rest sig) (conj result (->> sig
                                                  (take bc)
                                                  (reverse)
                                                  (map * b-vec)
                                                  (apply +)))))))) 


(time (def b (filt [1 2 3] (range 10000))))
=> "Elapsed time: 50.892536 msecs"
Run Code Online (Sandbox Code Playgroud)


mik*_*era 6

如果你真的想要这种计算的最佳性能,你应该使用数组而不是矢量.阵列具有许多性能优势:

  • 它们支持O(1)索引查找和写入 - 比O(log32 n)的向量略胜一筹
  • 它们是可变的,因此您不需要一直构造新的数组 - 您只需创建一个数组作为输出缓冲区
  • 它们在引擎盖下表示为Java数组,因此可以从JVM中内置的各种数组优化中受益
  • 您可以使用原始数组(例如Java双精度数组),它比使用盒装数字对象快得多

代码将是这样的:

(defn filt [^doubles b-arr 
            ^doubles x-arr]
     (let [bc (count b-arr) 
           xc (count x-arr)
           rc (inc (- xc bc))
           result ^doubles (double-array rc)]
       (dotimes [i rc]
         (dotimes [j bc]
           (aset result i (+ (aget result i) (* (aget x-arr (+ i j)) (aget b-arr j))))))
       result))
Run Code Online (Sandbox Code Playgroud)