【发布时间】:2017-06-09 09:55:31
【问题描述】:
我是 Clojure 的新手,我在 2 个月前开始学习这门语言。我正在阅读“clojure 的乐趣”一书,并在函数式编程主题中找到了一个 min-by 函数。我在想,我已经完成了我的 min-by 函数,这在至少 10.000 个项目上似乎至少提高了 50% 的性能。下面是函数
; the test vector with random data
(def my-rand-vec (vec (take 10000 (repeatedly #(rand-int 10000)))))
; the joy of clojure min-by
(defn min-by-reduce [f coll]
(when (seq coll)
(reduce (fn [min other]
(if (> (f min) (f other))
other
min))
coll)))
(time (min-by-reduce eval my-rand-vec))
; my poor min-by
(defn min-by-sort [f coll]
(first (sort (map f coll))))
(time (min-by-sort eval my-rand-vec))
终端输出是
"Elapsed time: 91.657505 msecs"
"Elapsed time: 62.441513 msecs"
我的解决方案是否存在性能或资源缺陷?我真的很好奇 clojure Gurus 为这个功能提供了更优雅的 clojure 解决方案。
编辑
带有标准的更清晰的测试代码。
(ns min-by.core
(:gen-class))
(use 'criterium.core)
(defn min-by-reduce [f coll]
(when (seq coll)
(reduce (fn [min other]
(if (> (f min) (f other))
other
min))
coll)))
(defn min-by-sort [f coll]
(first (sort-by f coll)))
(defn my-rand-map [length]
(map #(hash-map :resource %1 :priority %2)
(take length (repeatedly #(rand-int 200)))
(take length (repeatedly #(rand-int 10)))))
(defn -main
[& args]
(let [rand-map (my-rand-map 100000)]
(println "min-by-reduce-----------")
(quick-bench (min-by-reduce :resource rand-map))
(println "min-by-sort-------------")
(quick-bench (min-by-sort :resource rand-map))
(println "min-by-min-key----------")
(quick-bench (apply min-key :resource rand-map)))
)
终端输出是:
min-by-reduce-----------
Evaluation count : 60 in 6 samples of 10 calls.
Execution time mean : 11,366539 ms
Execution time std-deviation : 2,045752 ms
Execution time lower quantile : 9,690590 ms ( 2,5%)
Execution time upper quantile : 14,763746 ms (97,5%)
Overhead used : 3,292762 ns
Found 1 outliers in 6 samples (16,6667 %)
low-severe 1 (16,6667 %)
Variance from outliers : 47,9902 % Variance is moderately inflated by outliers
min-by-sort-------------
Evaluation count : 6 in 6 samples of 1 calls.
Execution time mean : 174,747463 ms
Execution time std-deviation : 18,431608 ms
Execution time lower quantile : 158,138543 ms ( 2,5%)
Execution time upper quantile : 203,420044 ms (97,5%)
Overhead used : 3,292762 ns
Found 1 outliers in 6 samples (16,6667 %)
low-severe 1 (16,6667 %)
Variance from outliers : 30,7324 % Variance is moderately inflated by outliers
min-by-min-key----------
Evaluation count : 36 in 6 samples of 6 calls.
Execution time mean : 17,405529 ms
Execution time std-deviation : 1,661902 ms
Execution time lower quantile : 15,962259 ms ( 2,5%)
Execution time upper quantile : 19,366893 ms (97,5%)
Overhead used : 3,292762 ns
【问题讨论】:
-
如果您想尝试一下,
eval是一个糟糕的选择。您的整个运行时都由它主导。你变慢的原因是你在你的 reduce 版本中调用了eval2*N 而在你的sort版本中只调用了N次。 -
谢谢!我已将
eval更改为identity,结果完全改变了。 100.000 个项目的终端输出是"Elapsed time: 8.234689 msecs" "Elapsed time: 131.30328 msecs"
标签: clojure