Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Clojure 1.3中的函数性能_Performance_Clojure - Fatal编程技术网

Performance Clojure 1.3中的函数性能

Performance Clojure 1.3中的函数性能,performance,clojure,Performance,Clojure,我想知道是否有人可以帮助我在Clojure 1.3中实现这个代码片段。我正在尝试实现一个简单的函数,它接受两个向量并求和乘积 假设向量是X(大小10000个元素)和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,对应于(10000-3)。我已经将函数设置为接受任意大小的X和B 下面是代码:它基本上从X开始一次提取(

我想知道是否有人可以帮助我在Clojure 1.3中实现这个代码片段。我正在尝试实现一个简单的函数,它接受两个向量并求和乘积

假设向量是X(大小10000个元素)和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,对应于(10000-3)。我已经将函数设置为接受任意大小的X和B

下面是代码:它基本上从X开始一次提取
(计数b)
元素,将其反转,将
*
映射到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 +)))))))
当X为
(vec(范围1 10001))
且B为
[1 2 3]
时,此函数运行大约需要6秒。我希望有人能对运行时提出改进建议,无论是算法方面的改进,还是我可能滥用的语言细节方面的改进

谢谢


另外,我已经完成了
(设置!*反射时发出警告*true)
,但没有收到任何反射警告消息。

您多次使用count。以下代码仅计算一次计数

(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"

为了继续学习Ankur的优秀答案,您还可以避免重复调用reverse函数,这会使我们的性能更高一些

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

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

  • 它们支持O(1)索引查找和写入-略优于O(log32n)向量
  • 它们是可变的,因此您不需要一直构造新的数组-您只需创建一个数组作为输出缓冲区即可
  • 它们在引擎盖下表示为Java数组,因此可以从JVM中内置的各种数组优化中获益
  • 您可以使用基本数组(例如Java Double数组),这比使用装箱数字对象快得多
代码类似于:

(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))

也可以通过将B向量反转一次而不是将X向量的部分反转数百次来避免重复调用reverse吗?我不知道Clojure,但这似乎需要做很多额外的工作。实际上,反向调用是针对从x-vec获取的元素(即sig正在被反转)如果x-vec的大小为10000,那么我们将不得不进行3333次调用以反转我们从中获取的3个元素集,不是吗?但是如果我们只反转一次b-vec,我们应该能够避免它们。或者可能是半夜,我可能需要睡觉。是的,这可能是一个优化,这将使
Y0=B0*X2+B1*X1+B2*X0
操作到
Y0=B2*X0+B1*X1+B0*X2
。。好吧,我也会把它作为第二答案贴出来。你已经得到了我的+1。我发现了一个很棒的尝试Clojure在线页面…也许我应该看看这种语言。这很有趣。所以我尝试了这个版本,并让它运行。我将b-vec和x-vec转换为如下Java数组:
(def b-arr(转换为数组双b-vec))
(def x-arr(转换为数组双x-vec))
。然而,这个版本的代码运行速度比Ankur和Ian提供的优化版本慢得多。平均而言,纯功能版本大约为25毫秒,而Java阵列版本大约为850毫秒。有什么建议吗?您需要为
b-arr
x-arr
使用基本数组。试试
(def b-arr(double-array b-vec))
好的,我明白了为什么这个原生Java版本很慢。我用
defn filt[^doubles b-arr^ doubles x-arr]
替换了
defn filt[b-arr x-arr]
,它运行得非常快。谢谢你的回答,希望我也能把你的回答标记为接受。整个练习对我很有帮助。啊,看起来我是在你添加评论时添加的,直到我发布后才注意到。无论如何,我也尝试了你的建议,但是必须键入函数的参数来观察巨大的加速。我认为使用本机Java数组的缺点是,它会失去不可变持久数据结构的并发特性。