rao*_*oof 5 performance awt clojure
这是一个简单的代码,只对窗口着色4次.
也许有一些我看不到的明显事物.
我的目标是从头开始学习计算机图形,我想逐个像素地绘制以完全控制.我正在寻找一种快速的方法来做到这一点.
这是完整的代码.
相关的clojure部分:
(defmacro for-loop [[sym init check change :as params] & steps]
`(loop [~sym ~init value# nil]
(if ~check
(let [new-value# (do ~@steps)]
(recur ~change new-value#))
value#)))
(time
(for-loop
[k 0 (< k 2) (inc k)]
(for-loop
[c 0 (< c 2) (inc c)]
(for-loop
[i 0 (< i width) (inc i)]
(for-loop
[j 0 (< j height) (inc j)]
(aset ^ints @pixels (+ i (* j width)) (get cs c))))
(.repaint canvas))))
Run Code Online (Sandbox Code Playgroud)
java中的相同代码:
long t = System.currentTimeMillis();
for (int k = 0 ; k < 2; k++) {
for (int c = 0; c < 2; c++) {
for (int i = 0 ; i < width; i++) {
for (int j = 0; j < height; j++) {
pixels[i + j * width] = cs[c];
}
}
repaint();
}
}
System.out.println(System.currentTimeMillis() - t);
Run Code Online (Sandbox Code Playgroud)
有几个问题:
如果你跑lein check
,你会看到反射警告.你在运行时强制反射会降低速度.我将canvas
创建更改为:
(defonce canvas (doto (proxy [Frame] []
(update [g] (.paint this g))
(paint [^Graphics2D g]
(.drawImage g, ^BufferedImage image, 0, 0 nil)))
(.setSize width height)
(.setBackground Color/black)
(.setFocusableWindowState false)
(.setVisible true)))
Run Code Online (Sandbox Code Playgroud)
注意我正在使用的类型提示.它不知道使用哪个重载drawImage
,并且完全找不到该paint
方法.
然而,主要问题是使用aset
.来自aset
的文档:
设置索引/索引处的值.适用于引用类型的Java数组.返回val.
强调我的.
问题是aset
不适用于基元.它强制将每个数字包装为a Integer
,然后在图像中使用时再次打开.当在图像的每个像素上相乘时,这是非常昂贵的.
更改aset
为aset-int
使用int
基元.这将执行时间从大约20秒缩短到半秒.
老实说,我不能低估它.它比它快得多,但仍然比Java版本慢约20倍.我现在已经工作了将近2个小时,而且我已经撞墙了.希望其他人可以挤出最后一点时间.