Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.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

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性能,如何向r/map键入提示_Performance_Clojure_Type Hinting_Reducers - Fatal编程技术网

Performance Clojure性能,如何向r/map键入提示

Performance Clojure性能,如何向r/map键入提示,performance,clojure,type-hinting,reducers,Performance,Clojure,Type Hinting,Reducers,下面,我有两个函数计算它们参数的平方和。第一个很好,功能齐全,但比第二个慢20倍。我假设r/map没有利用aget从双数组中检索元素,而我在函数2中显式地这样做 我有没有办法进一步输入提示或帮助r/映射r/折叠以更快地执行 (defn sum-of-squares "Given a vector v, compute the sum of the squares of elements." ^double [^doubles v] (r/fold + (r/map #(* % %)

下面,我有两个函数计算它们参数的平方和。第一个很好,功能齐全,但比第二个慢20倍。我假设r/map没有利用aget从双数组中检索元素,而我在函数2中显式地这样做

我有没有办法进一步输入提示或帮助r/映射r/折叠以更快地执行

(defn sum-of-squares
  "Given a vector v, compute the sum of the squares of elements."
  ^double [^doubles v]
  (r/fold + (r/map #(* % %) v)))

(defn sum-of-squares2
  "This is much faster than above.  Post to stack-overflow to see."
  ^double [^doubles v]
  (loop [val 0.0
         i (dec (alength v))]
    (if (neg? i)
      val
      (let [x (aget v i)]
        (recur (+ val (* x x)) (dec i))))))

(def a (double-array (range 10)))
(quick-bench (sum-of-squares a))
800纳秒

(quick-bench (sum-of-squares2 a))

40纳秒

在实验之前,我在project.clj中添加了下一行:

:jvm-opts ^:replace [] ; Makes measurements more accurate
基本测量:

(def a (double-array (range 1000000))) ; 10 is too small for performance measurements
(quick-bench (sum-of-squares a)) ; ... Execution time mean : 27.617748 ms ...
(quick-bench (sum-of-squares2 a)) ; ... Execution time mean : 1.259175 ms ...
这或多或少与问题中的时差一致。让我们尽量不要使用Java数组(对于Clojure来说,Java数组并不是真正惯用的):

几乎快了2倍。现在,让我们删除类型提示:

(defn sum-of-squares3
"Given a vector v, compute the sum of the squares of elements."
[v]
(r/fold + (r/map #(* % %) v)))

(quick-bench (sum-of-squares3 a)) ; Execution time mean : 30.392206 ms
(quick-bench (sum-of-squares3 b)) ; Execution time mean : 15.583379 ms
与具有类型提示的版本相比,执行时间仅略微增加。顺便说一下,具有的版本具有非常相似的性能,并且更干净:

(defn sum-of-squares3 [v]
  (transduce (map #(* % %)) + v))
现在,关于附加类型提示。我们确实可以首先优化
平方和
实现:

(defn square ^double [^double x] (* x x))

(defn sum-of-squares4
  "Given a vector v, compute the sum of the squares of elements."
  [v]
  (r/fold + (r/map square v)))

(quick-bench (sum-of-squares4 b)) ; ... Execution time mean : 12.891831 ms ...

(defn pl
  (^double [] 0.0)
  (^double [^double x] (+ x))
  (^double [^double x ^double y] (+ x y)))

(defn sum-of-squares5
  "Given a vector v, compute the sum of the squares of elements."
  [v]
  (r/fold pl (r/map square v)))

(quick-bench (sum-of-squares5 b)) ; ... Execution time mean : 9.441748 ms ...
注#1:
sum-of-squares4
sum-of-squares5
的参数和返回值的类型提示没有额外的性能优势

注意#2:一开始通常是不好的做法。直接版本
(apply+(map square v))
在大多数情况下都有足够好的性能
sum-of-squares2
远远不是惯用语,它实际上没有使用Clojure概念。如果这真的是性能关键的代码,最好用Java实现并使用互操作。尽管有两种语言,但代码将更加干净。甚至可以在非托管代码(C、C++)中实现它,并使用JNI(不是真正可维护的,但如果正确实现,可以提供最佳性能)。

为什么不使用:

在我运行的机器上:

(criterium/bench (sum-of-squares3 (double-array (range 100000))))
平均执行时间为1.809103 ms,您的
sum-of-squares2
以1.455775 ms执行相同的计算。我认为使用
areduce
的此版本比您的版本更为惯用

为了压缩更多的性能,您可以尝试使用未经检查的数学(和)。但请注意,您需要确保您的计算不会溢出:

(defn sum-of-squares4 ^double [^doubles v]
  (areduce v idx ret 0.0
           (let [item (aget v idx)]
             (unchecked-add ret (unchecked-multiply item item)))))

运行同一个基准测试的平均执行时间为1.144197毫秒。您的
平方和2
也可以从平均执行时间为1.126001毫秒的未检查数学中受益。

谢谢。我知道我的v2不是惯用的,但代码对性能非常敏感(数万亿次计算),我不希望每次有热代码补丁时都要使用java。我当然更喜欢使用通用的clojure风格的版本,但即使是10:1的性能下降也是相当明显的。因此,对于这个特定的应用程序,我将坚持使用v2。我只是想把我的蛋糕也吃了…用你的传感器v3的优雅来接近v2的性能。换句话说,我把v2当作互操作的一部分,没有两种语言的开销。谢谢Rodrigo。我不知道阿雷德。这正是我所需要的,一种告诉减少使用aget。。。
(criterium/bench (sum-of-squares3 (double-array (range 100000))))
(defn sum-of-squares4 ^double [^doubles v]
  (areduce v idx ret 0.0
           (let [item (aget v idx)]
             (unchecked-add ret (unchecked-multiply item item)))))