Clojure - 优化线程映射减少
Clojure - optimize a threaded map reduce
我有以下代码:
(defn series-sum
"Compute a series : (+ 1 1/4 1/7 1/10 1/13 1/16 ...)"
[n]
(->> (iterate (partial + 3) 1)
(map #(/ 1 %))
(take n)
(reduce +)
float
(format "%.2f")
(str)))
它工作得很好,只是 运行 数字变大时时间会爆炸。在我的电脑上 (series-sum 2500)
可能是一两秒,但是 (series-sum 25000)
我必须关闭我的 REPL。
我尝试尽可能地移动 (take n)
,但这还不够。我觉得我对 Clojure 不太了解,因为我不明白为什么它会变慢(我预计 (series-sum 25000)
大约需要 (series-sum 2500)
的 10 倍)。
有一个明显的 loop/recur 解决方案来优化它,但我喜欢能够打印步骤并有一个步骤的想法((take n)
看起来像文档字符串)。
如何在保持可调试性的同时提高此代码的性能?
更好的是,我可以测量每一步的时间以查看花费的时间吗?
是的,它与@zerkms 的 link 有关。你映射到有理数,可能最好映射到浮点数:
(defn series-sum
"Compute a series : (+ 1 1/4 1/7 1/10 1/13 1/16 ...)"
[n]
(->> (iterate (partial + 3) 1)
(take n)
(map #(/ 1.0 %))
(reduce +)
(format "%.2f")))
现在运行速度更快:
user> (time (series-sum 2500000))
"Elapsed time: 686.233199 msecs"
"5,95"
对于这种类型的数学运算,循环计算比使用惰性序列更快。这比我的其他答案快一个数量级:
(defn series-sum
[n]
(loop [i 0
acc 0.0]
(if (< i n)
(recur (inc i)
(+ acc (/ (float 1) (inc (* 3 i)))))
(format "%.2f" acc))))
注意:您不需要 str
因为 format
returns 一个字符串。
编辑:当然这不是原始问题中代码的主要问题。如其他答案所示,大部分改进来自消除有理数。这只是进一步的优化。
我有以下代码:
(defn series-sum
"Compute a series : (+ 1 1/4 1/7 1/10 1/13 1/16 ...)"
[n]
(->> (iterate (partial + 3) 1)
(map #(/ 1 %))
(take n)
(reduce +)
float
(format "%.2f")
(str)))
它工作得很好,只是 运行 数字变大时时间会爆炸。在我的电脑上 (series-sum 2500)
可能是一两秒,但是 (series-sum 25000)
我必须关闭我的 REPL。
我尝试尽可能地移动 (take n)
,但这还不够。我觉得我对 Clojure 不太了解,因为我不明白为什么它会变慢(我预计 (series-sum 25000)
大约需要 (series-sum 2500)
的 10 倍)。
有一个明显的 loop/recur 解决方案来优化它,但我喜欢能够打印步骤并有一个步骤的想法((take n)
看起来像文档字符串)。
如何在保持可调试性的同时提高此代码的性能?
更好的是,我可以测量每一步的时间以查看花费的时间吗?
是的,它与@zerkms 的 link 有关。你映射到有理数,可能最好映射到浮点数:
(defn series-sum
"Compute a series : (+ 1 1/4 1/7 1/10 1/13 1/16 ...)"
[n]
(->> (iterate (partial + 3) 1)
(take n)
(map #(/ 1.0 %))
(reduce +)
(format "%.2f")))
现在运行速度更快:
user> (time (series-sum 2500000))
"Elapsed time: 686.233199 msecs"
"5,95"
对于这种类型的数学运算,循环计算比使用惰性序列更快。这比我的其他答案快一个数量级:
(defn series-sum
[n]
(loop [i 0
acc 0.0]
(if (< i n)
(recur (inc i)
(+ acc (/ (float 1) (inc (* 3 i)))))
(format "%.2f" acc))))
注意:您不需要 str
因为 format
returns 一个字符串。
编辑:当然这不是原始问题中代码的主要问题。如其他答案所示,大部分改进来自消除有理数。这只是进一步的优化。