【发布时间】:2016-08-16 12:21:04
【问题描述】:
我在调整一些性能敏感代码时遇到了这个问题:
user> (use 'criterium.core)
nil
user> (def n (into {} (for [i (range 20000) :let [k (keyword (str i))]] [k {k k}])))
#'user/n
user> (quick-bench (-> n :1 :1))
WARNING: Final GC required 32.5115186521176 % of runtime
Evaluation count : 15509754 in 6 samples of 2584959 calls.
Execution time mean : 36.256135 ns
Execution time std-deviation : 1.076403 ns
Execution time lower quantile : 35.120871 ns ( 2.5%)
Execution time upper quantile : 37.470993 ns (97.5%)
Overhead used : 1.755171 ns
nil
user> (quick-bench (get-in n [:1 :1]))
WARNING: Final GC required 33.11057826481865 % of runtime
Evaluation count : 7681728 in 6 samples of 1280288 calls.
Execution time mean : 81.023429 ns
Execution time std-deviation : 3.244516 ns
Execution time lower quantile : 78.220643 ns ( 2.5%)
Execution time upper quantile : 85.906898 ns (97.5%)
Overhead used : 1.755171 ns
nil
对我来说,get-in 的速度比通过gets 的速度慢两倍以上,这对我来说是不直观的,因为get-in 似乎被定义为这类事情的更好抽象。
有没有人知道为什么会这样(技术上和哲学上)?
【问题讨论】:
-
如果您查看这两个函数的源代码,您会发现
get-in中进行了一些递归,允许它梳理嵌套结构。我猜这就是额外开销的来源。 -
我只能猜测 get-in 是一个更“通用”的功能,而且开销更大。在我的电脑上,它并没有那么糟糕,分别为 31 ns 和 57 ns。
标签: clojure