阅读了一些关于这个主题的博客文章后,我发现在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)))
平均花费了14ms,而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。 **
我是否竭尽所能让事情变得更快,还有什么可以进入优化路径吗?
**我使用(report-result (bench (m xs ys )) :verbose)
和(report-result (bench (. Test m xs ys)) :verbose)
答案 0 :(得分: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
。
答案 1 :(得分: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)))))