这是一个简单的代码,仅将窗口着色4次。

也许有些明显的东西我看不到。

我的目标是从头学习计算机图形,我想逐个像素绘制以完全控制。我正在寻找一种快速的方法。

Here是完整代码。

相关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))))

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);

最佳答案

有几个问题:

  • 如果您运行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)))
    

    注意我正在使用的类型提示。它不知道要使用哪种drawImage重载,并且根本找不到paint方法。
  • 然而,主要问题是aset的使用。从aset的文档中:



    强调我的。

    问题在于aset不适用于原语。它将每个数字强制包装为Integer,然后在图像中使用该数字时再次将其解包。当乘以图像的每个像素时,这是非常昂贵的。

    aset更改为aset-int,以改为使用int基元。这将使执行时间从大约20秒减少到半秒。


  • 老实说,我不能再降低了。它比以前快很多,但仍然比Java版本慢20倍。我已经为此工作了将近2个小时,而且碰壁了。希望其他人可以减少最后的超时时间。

    关于performance - 寻找一种逐像素绘制的快速方法,为什么此代码比Java慢1000倍?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49956224/

    10-12 07:33