6

在阅读了一些关于该主题的博客文章后,我发现在 Clojure 中对数组进行变异是这样的:

(defn m [xs ys] 
  (dotimes [i (count xs)] 
    (aset #^ints ys (int i) 
    (int (* (int 3) (int (aget #^ints xs (int i))))))))

在哪里(def xs (into-array Integer/TYPE (range 1000000)))(def ys (into-array Integer/TYPE (range 1000000)))

根据 Criterium,平均需要 14 毫秒,而 Java 也是如此,

public static int[] m(int[] x, int[] y)
{
  for(int i=0; i<x.length; i++)
    y[i] = 3*x[i];
  return y;
}

平均需要800us。**

我是否正在尽我所能让事情进展得更快,我还有什么可以沿着优化路径走下去的吗?

** 我使用 Criterium(report-result (bench (m xs ys )) :verbose)(report-result (bench (. Test m xs ys)) :verbose)

4

2 回答 2

5

如果你想要速度,你需要进入原始世界,在完成之前不要离开它。从盒装开始Integer i,然后在每个使用站点将其转换为原语是没有用的。也许您可以dotimes制作整数(类型提示 的声明i),但不确定。我所知道的是一个loop-recur带有循环变量原始初始化器的构造:(loop [i (int 0)] ... (recur (unchecked-inc i)). 此外,在您的示例中,您有(int 3). 您需要let提前这样做,以免在每次迭代中重复拆箱。

顺便说一句,您可以使用(int-array (range 1000000))创建初始化数组并仅(int-array 1000000)用于空数组。

更新

从 Clojure 1.3 开始,由于对原语的支持得到了增强,我上面写的大部分内容都不再适用了。dotimes已经使用了原始算术,因此您需要编写的所有内容才能获得完整的性能

(dotimes [i (alength ^ints xs)] 
  (aset ^ints ys i (unchecked-multiply (aget ^ints xs i) 3)

基本上,不需要int构造函数,并且使用unchecked-multiply.

于 2012-04-16T08:04:45.873 回答
5

在 Clojure 1.3 上试试这个:

(set! *unchecked-math* true)

(defn m [^longs xs ^longs ys]
  (dotimes [i (count xs)]
    (aset ys i
      (* 3 (aget xs i)))))
于 2012-04-16T15:39:40.047 回答