Sav*_*nel 7 clojure mathematical-optimization micro-optimization
我有一组少量的功能.两个函数进行数学叠加操作(定义http://docs.gimp.org/en/gimp-concepts-layer-modes.html,但有点下来-只要搜索"叠加",找到数学)在不同的方法.现在,这个操作是Gimp在一秒钟之内做得很快的事情,但是我似乎无法优化我的代码以获得类似于远程类似时间的任何东西.
(我的应用程序是一个GUI应用程序,可以帮助我查看和比较大量文件的各种叠加组合.Gimp层界面实际上很难选择两个图像叠加,然后选择不同的两个,等等)
这是代码:
(set! *warn-on-reflection* true )
(defn to-8-bit [v]
(short (* (/ v 65536) 256)))
(defn overlay-sample [base-p over-p]
(to-8-bit
(* (/ base-p 65536)
(+ base-p
(* (/ (* 2 over-p) 65536)
(- 65536 base-p))))))
(defn overlay-map [^shorts base ^shorts over]
(let [ovl (time (doall (map overlay-sample ^shorts base ^shorts over)))]
(time (into-array Short/TYPE ovl))))
(defn overlay-array [base over]
(let [ovl (time (amap base
i
r
(int (overlay-sample (aget r i)
(aget over i)))))]
ovl))
Run Code Online (Sandbox Code Playgroud)
overlay-map和overlay-array以不同的方式执行相同的操作.我也写了这个操作的其他版本.然而,到目前为止,叠加图是我所拥有的最快的.
base和over两个函数都是16位整数数组.每个样本的实际大小为1,276,800个样本(800 x 532图像,每个像素3个样本).最终结果应该是相同的单个数组,但缩小到8位.
我(时间)操作的结果非常一致.overlay-map在大约16或17秒内运行实际的数学运算,然后花费另外5秒将结果序列复制回整数数组.
overlay-array大约需要111秒.
我已经做了很多关于使用数组,类型提示等的阅读,但我的Java-Array-Only操作非常慢!amap,aget等都应该是快速的,但是我已经阅读了代码,并且没有什么看起来像速度优化,我的结果是一致的.我甚至尝试过其他电脑,看到的差别大致相同.
现在,16-17秒,实际上在这个数据集上相当痛苦,但我一直在缓存结果,以便我可以轻松地来回切换.如果我将数据集的大小增加到像全尺寸图像(4770x3177)这样的任何东西,那么相同的操作将花费很长的时间.而且,我还想做其他的操作.
那么,有关如何提高速度的任何建议吗?我在这里错过了什么?
更新:我刚才提出有关这一代码公开了整个项目,所以你可以看到我在使用速度测试的当前版本整个脚本https://bitbucket.org/savannidgerinel/hdr-darkroom/src/62a42fcf6a4b/scripts/ speed_test.clj.随意下载并在自己的设备上试用,但显然在运行之前更改图像文件路径.
由于您的函数纯粹是数学函数,因此您可能需要查看 memoize
(def fast-overlay (memoize overlay-sample))
(time (fast-overlay 1000 2000))
"Elapsed time: 1.279 msecs"
(time (fast-overlay 1000 2000))
"Elapsed time: 0.056 msecs"
Run Code Online (Sandbox Code Playgroud)
这里发生的情况是参数被缓存为键,返回的是值。如果已经计算了值,则返回该值而不是执行的函数。