如何提高clojure中在两个数组上运行的函数的性能

如何提高clojure中在两个数组上运行的函数的性能,clojure,micro-optimization,mathematical-optimization,Clojure,Micro Optimization,Mathematical Optimization,我有一组少量的函数。这两个函数以不同的方式执行数学覆盖操作(在上定义,但稍微向下——只需搜索“覆盖”即可找到数学)。现在,这个操作是Gimp在不到一秒钟的时间内快速完成的,但我似乎无法优化我的代码以获得类似于远程相似的时间 (我的应用程序是一个GUI应用程序,可以帮助我查看和比较大量文件的各种覆盖组合。Gimp层界面实际上使得只选择两个要覆盖的图像,然后选择另两个图像相当困难,等等。) 代码如下: (set! *warn-on-reflection* true ) (defn to-8-bit

我有一组少量的函数。这两个函数以不同的方式执行数学覆盖操作(在上定义,但稍微向下——只需搜索“覆盖”即可找到数学)。现在,这个操作是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))
叠加贴图和叠加数组以不同的方式执行相同的操作。我也写过这个操作的其他版本。然而,叠加贴图是目前为止我拥有的最快的

在这两个函数中,base和over都是16位整数数组。每个图像的实际大小为1276800个样本(800 x 532图像,每个像素3个样本)。最终的结果应该是相同的单个数组,但缩小到8位

我的(时间)运算结果相当一致。叠加贴图在大约16或17秒内运行实际的数学运算,然后再花费5秒钟将结果序列复制回整数数组

覆盖阵列大约需要111秒

我已经读了很多关于使用数组、类型提示等的书,但是我的纯Java数组操作速度惊人地慢!amap、aget等都应该是快速的,但我已经阅读了代码,没有任何东西看起来像是速度优化,我的结果是一致的。我甚至试过其他电脑,也发现了大致相同的区别

现在,在这个数据集上,16-17秒实际上是相当痛苦的,但我一直在缓存结果,以便可以轻松地来回切换。如果我将数据集的大小增加到与全尺寸图像(4770x3177)类似的大小,同样的操作将花费非常长的时间。还有,我还想做其他的手术

那么,有没有关于如何加快这一进程的建议?我错过了什么


更新:我刚刚公开了与此代码相关的整个项目,因此您可以看到当前版本以及我用于速度测试的整个脚本。您可以随意下载并在自己的设备上试用,但在运行之前显然要更改图像文件路径。

由于您的函数纯粹是数学函数,您可能需要查看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"

这里发生的是参数被缓存为键,返回值。如果已经计算了值,则返回值,而不是执行函数。

您是否尝试过使用
^shorts
键入提示
base
over
?然后去掉你的
^Integer
类型提示,它什么也不做。是因为^Integer的位置,还是因为它不是有效的类型提示,它什么都不做?我假设^shorts(复数形式)适用于数组?
^Integer
做了一些事情,但在这里没有帮助(如果您愿意,您可以使用或不使用它来计时;我建议始终这样做,以及
(设置!*反射时警告*真)
)<代码>^shorts是shorts基元数组的类型提示。我会计时,看看是否有帮助。我无法修改覆盖数组(整数和短字符之间的一些ClassCastException,我还没有弄清楚),但我确实对覆盖映射进行了类型暗示更改。处理时间似乎一直下降到13秒,拷贝到阵列中的时间下降到300微秒左右。改进了很多,但仍然不是我需要的地方。不,1.2.1。1.3会添加一个有帮助的功能吗?我试过了。性能实际上下降了很多,以至于在测试运行了原来时间的三倍之后,我中止了测试。函数中有两个不同的16位值,如果重复的次数超过了非常小的次数,我会感到惊讶。