我在调整一些对性能敏感的代码时遇到了这个问题:
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
的速度是get
的{{1}}的两倍,因为get-in
似乎被定义为对此类事物的更好抽象,这是不直观的。
有没有人知道为什么会出现这种情况(技术上和哲学上)?
答案 0 :(得分:8)
嵌套地图在Clojure程序中非常常用。这是一件好事。但有时可以通过展开来改进嵌套地图操作,例如assoc-in
和get-in
。就生成的字节代码而言,(get :a (get :b (get :c (get :d m)))
与(get-in m [:d :c :b :a])
不同。后面的字节代码导致执行时间更短。
请注意,Clojure有一些与此相关的待处理补丁http://dev.clojure.org/jira/browse/CLJ-1656。