Performance 此功能的评估时间为85纳秒和10秒(!?) 客观的
我试图弄明白为什么我创建的函数,Performance 此功能的评估时间为85纳秒和10秒(!?) 客观的,performance,clojure,benchmarking,read-eval-print-loop,Performance,Clojure,Benchmarking,Read Eval Print Loop,我试图弄明白为什么我创建的函数,items-staged-f的计算时间既长又短 你说奇怪? 我说“奇怪”是因为: (时间(items-staged-f))产生1.313毫秒 (time(items-staged-f))第二次产生0.035毫秒(这并不奇怪,因为结果是一个延迟序列,必须已被记忆) 基准测试系统报告需要85.149767 ns(这并不奇怪) 然而 在REPL中实际评估(items-staged-f)所需的时间约为10秒。这甚至在它打印任何东西之前。我最初认为它可能需要这么长的时
items-staged-f
的计算时间既长又短
你说奇怪?
我说“奇怪”是因为:
产生(时间(items-staged-f))
1.313毫秒
第二次产生(time(items-staged-f))
(这并不奇怪,因为结果是一个延迟序列,必须已被记忆)0.035毫秒
- 基准测试系统报告需要
(这并不奇怪)85.149767 ns
- 在REPL中实际评估
所需的时间约为10秒。这甚至在它打印任何东西之前。我最初认为它可能需要这么长的时间,因为它准备打印到REPL,因为它是一个长而复杂的数据结构(嵌套的映射和向量以惰性顺序排列),但奇怪的是,结果甚至要到10秒后才开始打印,而这(假设)需要85纳秒。可能是因为它在预先计算如何打印数据结构(items-staged-f)
产生(时间(最后一次(items-staged-f))
(尽管这可能会在20秒左右变化),原因可能与上述相同10498.16毫秒
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-f
的输出在结构上几乎与items-staged
的输出相同,只是它是一个延迟的向量序列,而不是具有哈希映射项的哈希映射,这是通过调用哈希映射上的map
函数所期望的
in?
是检查对象是否在给定集合中的谓词。例如,(在?1[1 2 3])
的计算结果为true
组+行项目
是一个函数,它输出我希望消除的某些重复项目的延迟序列。例如,(组+行项目)
的计算结果为:(“428X”“41SF”“6998”“75D22”)
笔记
VisualVM 1.3.8表示clojure.lang.Reflector.getMethods()的时钟频率为28700毫秒(51.3%),clojure.lang.LineNumberingPushbackReader.read()的时钟频率为9000毫秒(16.2%),clojure.lang.RT.nthFrom()的时钟频率为7800毫秒(13.9%)
但是,当我在REPL中分别计算惰性序列(nth items-staged-fn)
的每个元素时,只有clojure.lang.LineNumberingPushbackReader.read()会上升。调用以32的增量递增,这是惰性seq分块大小。其他方法/功能所用的时间可以忽略不计
另一个需要考虑的问题是,items-staged
是一个最终从Excel文件(通过读取)中提取数据的函数。但是,Excel文件中的原始数据存储为var,因此这不应该成为问题,因为它在被存储之前只计算一次(我认为)
谢谢你的帮助强> 补遗
曾经我使用
doall
强制实现惰性序列(我认为该序列正在实现),Criterium现在说该函数需要11.370356秒
来计算,不幸的是这是有意义的。重构后我将重新发布。根据定义,惰性序列仅在需要时计算其元素。打印到REPL或请求last
元素都会强制实现。对生成延迟序列的函数调用进行计时并不重要
(defn slow-and-lazy [] (map #(do (Thread/sleep 1000) (inc %)) (range 10)))
user=> (time (slow-and-lazy))
"Elapsed time: 0.837002 msecs"
(1 2 3 4 5 6 7 8 9 10) ; printed 10 seconds later
user=> (time (doall (slow-and-lazy)))
"Elapsed time: 10000.205709 msecs"
(1 2 3 4 5 6 7 8 9 10)
在(time(slow and lazy))
的情况下,slow and lazy
快速返回一个未实现的延迟序列,time
完成,打印经过的时间,并将未实现的结果传递给REPL。然后,REPL尝试打印序列。为了做到这一点,它必须实现顺序
话虽如此,10秒对于一台计算机来说是永恒的,因此这确实值得检查/分析。我建议将代码重构为更小的自包含函数。特别是,数据应该作为参数传入。一旦你钉住瓶颈(时间用代码> DOALL < /代码>强制实现!),然后考虑发布一个新的问题。由于无法准确判断此代码发生了什么,或者
项目中的IO是否是真正的瓶颈,因此似乎仍有改进的余地。感谢您的帮助。我没有意识到,(时间(缓慢和懒惰))
会立即打印计时,但会实现打印计时的整个序列。我将重构代码并发布更新。@alexandergunnarson如果回答了直接的问题,您可以接受这个答案(在答案左边打勾)。然后,将发现的任何子问题作为新的单独问题发布。
(defn slow-and-lazy [] (map #(do (Thread/sleep 1000) (inc %)) (range 10)))
user=> (time (slow-and-lazy))
"Elapsed time: 0.837002 msecs"
(1 2 3 4 5 6 7 8 9 10) ; printed 10 seconds later
user=> (time (doall (slow-and-lazy)))
"Elapsed time: 10000.205709 msecs"
(1 2 3 4 5 6 7 8 9 10)