【发布时间】:2014-07-09 05:50:32
【问题描述】:
目标
我试图弄清楚为什么我创建的函数items-staged-f 的评估时间既长又短。
你说奇怪?
我说“奇怪”是因为:
-
(time (items-staged-f))产生1.313 msecs -
(time (items-staged-f))第二次产生0.035 msecs(这并不奇怪,因为结果是一个惰性序列,它一定是被记忆的) -
Criterium 基准测试系统报告它采用
85.149767 ns(这不足为奇)
然而……
- 在 REPL 中实际评估
(items-staged-f)所需的时间约为 10 秒。这甚至在它打印任何东西之前。我最初认为它可能需要很长时间,因为它准备打印到 REPL,因为它是一个长而复杂的数据结构(嵌套映射和向量在惰性序列中),但奇怪的是结果甚至不会开始打印到 10 秒后(据说)需要 85 纳秒。莫非是在预计算如何打印数据结构? -
(time (last (items-staged-f)))产生10498.16 msecs(尽管这可能会在 20 秒左右变化),原因可能与上述相同。
现在是代码...
函数items-staged-f 的目标是可视化需要做什么,以便对会计数据库中的库存项目进行一些必要的更改。
items-staged-f 中引用的不熟悉函数可以在下面找到。
(defn items-staged-f []
(let [items-0 (lazy-seq (items-staged :items))
both-types? #(in? % (group+line-items))
items-from-group #(get items-0 %)
replace-subgroups
(fn [[g-item l-items :as group]]
(let [items-in-both
(->> l-items
(map :item)
(filter both-types?))]
(->> (concat
(remove #(in? (:item %) items-in-both) l-items)
(mapcat items-from-group items-in-both))
(into [])
(assoc group 1))))
replaced (map replace-subgroups items-0)]
replaced))
items-staged 是输出items-staged-f 操作的原始数据的函数。 (items-staged :items) 输出带有字符串键(组项)的映射,其值是映射向量(子项列表):
{"786M" ; this is a group item
; below are the sub-items of the above group item
[{:description "Signature Collection Item", :item "4X1"}
{:description "Cookies, Inc. Paper Wrapped", :item "65G7"}
{:description "MyChocolate 5 oz.", :item "21F"}]}
请注意,items-staged-f 的输出在结构上与items-staged 的输出几乎相同,只是它是一个惰性向量序列,而不是一个带有 hash-map-entries 的 hash-map,如下所示预期通过在哈希映射上调用 map 函数。
in? 是一个谓词,用于检查对象是否在给定集合中。例如,(in? 1 [1 2 3]) 的计算结果为 true。
group+line-items 是一个函数,它输出我希望消除的某些重复项的惰性序列。例如,(group+line-items) 计算结果为:("428X" "41SF" "6998" "75D22")
注意事项
VisualVM 1.3.8 说 clojure.lang.Reflector.getMethods() 时钟在 28700 毫秒 (51.3%),clojure.lang.LineNumberingPushbackReader.read() (这是因为 REPL 中的输出?) 9000 毫秒 (16.2%),clojure.lang.RT.nthFrom() 7800 毫秒 (13.9%)。
但是,当我在 REPL 中单独评估惰性序列 (nth items-staged-f n) 的每个元素时,只有 clojure.lang.LineNumberingPushbackReader.read() 会上升。调用以 32 为增量增加,这是惰性序列分块大小。其他方法/功能所用的时间可以忽略不计。
另一个考虑因素是items-staged 是一个最终从 Excel 文件中提取数据的函数(通过Apache POI 读取)。但是,Excel 文件中的原始数据存储为 var,所以这应该不是问题,因为它只会在被记忆之前计算一次(我认为)。
感谢您的帮助!
附录
一旦我使用doall 强制实现惰性序列(我认为它正在实现),Criterium 现在说该函数需要11.370356 sec 来评估,不幸的是这是有道理的。重构后我会重新发布。
【问题讨论】:
标签: performance clojure benchmarking read-eval-print-loop