Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 如何在clojure数组处理中去掉clojure/lang/RT.aset和clojure/lang/RT.intCast?_Arrays_Performance_Clojure_Clojure Java Interop - Fatal编程技术网

Arrays 如何在clojure数组处理中去掉clojure/lang/RT.aset和clojure/lang/RT.intCast?

Arrays 如何在clojure数组处理中去掉clojure/lang/RT.aset和clojure/lang/RT.intCast?,arrays,performance,clojure,clojure-java-interop,Arrays,Performance,Clojure,Clojure Java Interop,我尝试在Clojure中使复数数组的乘法尽可能快 选择的数据结构是两个元素的映射,:re和:im,每个元素都是原语双的Java本机数组,以降低内存开销 据我所知,我对基元类型的数组使用了精确的类型规范 通过这些提示,aget被转换为本机数组dloadop,但是有两个低效,循环的计数器不是int,而是long,因此每次数组被索引时,计数器都会通过调用clojure/lang/RT.intCast转换为int。而且aset也不会转换为本机操作,而是转换为对clojure/lang/RT.aset的调

我尝试在Clojure中使复数数组的乘法尽可能快

选择的数据结构是两个元素的映射,
:re
:im
,每个元素都是原语
的Java本机数组,以降低内存开销

据我所知,我对基元类型的数组使用了精确的类型规范

通过这些提示,
aget
被转换为本机数组
dload
op,但是有两个低效,循环的计数器不是
int
,而是
long
,因此每次数组被索引时,计数器都会通过调用
clojure/lang/RT.intCast
转换为
int
。而且
aset
也不会转换为本机操作,而是转换为对
clojure/lang/RT.aset
的调用

另一个效率低下的问题是checkcast。它检查每个循环,确定数组实际上是双精度数组

结果是此Clojure代码的运行时间比等效Java代码的运行时间(不包括启动时间)多30%。这个函数可以在Clojure中重写以使其工作更快吗

Clojure代码,用于优化的函数是
multiply complex array

(def size 65536)

(defn get-zero-complex-array
    []
    {:re (double-array size)
     :im (double-array size)})

(defn multiply-complex-arrays
    [a b]
    (let [
        a-re-array (doubles (get a :re))
        a-im-array (doubles (get a :im))
        b-re-array (doubles (get b :re))
        b-im-array (doubles (get b :im))
        res-re-array (double-array size)
        res-im-array (double-array size)
        ]
        (loop [i (int 0) size (int size)]
            (if (< i size)
                (let [
                    a-re (aget a-re-array i)
                    a-im (aget a-im-array i)
                    b-re (aget b-re-array i)
                    b-im (aget b-im-array i)
                    ]
                    (aset res-re-array i (- (* a-re b-re) (* a-im b-im)))
                    (aset res-im-array i (+ (* a-re b-im) (* b-re a-im)))
                    (recur (unchecked-inc i) size))
                {:re res-re-array :im res-im-array}))))

(let [
    res (loop [i (int 0) a (get-zero-complex-array)]
            (if (< i 30000)
                (recur (inc i) (multiply-complex-arrays a a))
                a))
    ]
    (println (aget (get res :re) 0)))
Java代码:

class ComplexArray {

    static final int SIZE = 1 << 16;

    double re[];

    double im[];

    ComplexArray(double re[], double im[]) {
        this.re = re;
        this.im = im;
    }

    static ComplexArray getZero() {
        return new ComplexArray(new double[SIZE], new double[SIZE]);
    }

    ComplexArray multiply(ComplexArray second) {
        double resultRe[] = new double[SIZE];
        double resultIm[] = new double[SIZE];
        for (int i = 0; i < SIZE; i++) {
            double aRe = this.re[i];
            double aIm = this.im[i];
            double bRe = second.re[i];
            double bIm = second.im[i];
            resultRe[i] = aRe * bRe - aIm * bIm;
            resultIm[i] = aRe * bIm + bRe * aIm;
        }
        return new ComplexArray(resultRe, resultIm);
    }

    public static void main(String args[]) {
        ComplexArray a = getZero();
        for (int i = 0; i < 30000; i++) {
            a = a.multiply(a);
        }
        System.out.println(a.re[0]);
    }
}
  13: iload         4
  15: ldc           #5                  // int 65536
  17: if_icmpge     92
  20: aload_0
  21: getfield      #2                  // Field re:[D
  24: iload         4
  26: daload
  27: dstore        5
  29: aload_0
  30: getfield      #3                  // Field im:[D
  33: iload         4
  35: daload
  36: dstore        7
  38: aload_1
  39: getfield      #2                  // Field re:[D
  42: iload         4
  44: daload
  45: dstore        9
  47: aload_1
  48: getfield      #3                  // Field im:[D
  51: iload         4
  53: daload
  54: dstore        11
  56: aload_2
  57: iload         4
  59: dload         5
  61: dload         9
  63: dmul
  64: dload         7
  66: dload         11
  68: dmul
  69: dsub
  70: dastore
  71: aload_3
  72: iload         4
  74: dload         5
  76: dload         11
  78: dmul
  79: dload         9
  81: dload         7
  83: dmul
  84: dadd
  85: dastore
  86: iinc          4, 1
  89: goto          13

您如何对该代码进行基准测试?我建议使用criterium之类的工具,或者至少在比较时间之前执行多次。当天气足够暖和时,像checkcast这样的东西应该通过JIT进行优化。我还建议使用最新的JVM、-server和-XX:+AggressiveOpts

一般来说,我发现最好不要强迫Clojure在循环中使用int,而是使用long作为循环计数器,使用
(set!*unchecked math*true)
,并让Clojure在索引到数组时将long向下转换为int。虽然这看起来像是额外的工作,但我对现代硬件/JVM/JIT的印象是,差异远小于您的预期(因为您主要使用64位整数)。另外,看起来您将size作为循环变量进行传递,但它永远不会改变-也许您这样做是为了避免与i的类型不匹配,但我只会让size(作为long)在循环之前,并对i进行长增量和比较

有时,您可以通过在循环之前进行一些操作来减少校验。虽然很容易看到代码并在不需要的时候说出来,但编译器并没有真正对此进行任何分析,而是将其留给JIT来优化(它通常非常擅长,或者在99%的代码中这并不重要)

(设置!*未选中的数学*:装箱时发出警告)
(定义^long^:常量大小65536)
(defn获取零复杂数组[]
{:re(双数组大小)
:im(双数组大小)})
(defn乘法复数数组[ab]
(让[a-re-array(double(得到a:re))
a-im-array(双倍(获得a:im))
b-re阵列(双倍(获得b:re))
b-im阵列(双倍(获得b:im))
res re数组(双数组大小)
res im阵列(双倍阵列大小)
s(长码)]
(循环[i0]
(如果(
为什么不直接使用Clojure的Java实现?@OlegTheCat有可能,我只是想知道是否有一种意识形态的方式来编写Clojure代码,Clojure编译器可以创建最佳代码。@OlegTheCat有趣的引语是“生成的代码速度完全相同”。我不知道该示例是规则(Clojure中的数组处理可能是有效的)还是异常。@SamEstep获取程序集的具体步骤:1<代码>lein新应用程序tmp2。编辑tmp/src/tmp/code.clj-place
def size
defn get zero complex array
defn multiply complex array
介于
(:gen class))
(defn-main
.3.
lein-uberjar
4.从target/uberjar/tmp-0.1.0-SNAPSHOT.jar 5.提取tmp/core$multiply\u complex\u array.class.
src
(set!*未选中的数学*true)
intCast
调用转换为
l2i
指令在使用
*未检查的数学*
后时间从1.34 java变为1.22 java,在将
大小移出循环并重新循环到let后(比您建议在双数组中使用它时高出2行),时间到了1.17 java,使用
^long^:const
i
类型
long
时间到了1.15 java。Alex,谢谢你的宝贵建议。我在Windows下使用
time
程序的输出测量墙时间。我运行了5次,得到了中值。要得到java时间的倍数,我减去执行30000次循环和在Java和Clojure中执行1个循环的时间,然后将Clojure差异除以Java差异。问题与竞争性编程有关,因此代码没有时间运行超过10秒,因此我不会在几分钟的预热后对其进行测量。是
(设置!*未选中的数学*:框中警告)
全局设置?如何仅将其应用于一个函数或一个循环?
*未经检查的数学*
是一个动态变量,因此它既有根绑定(false),也可以基于每个线程进行设置(此处)。它不能仅应用于一个函数或循环,除非您制作一个宏来设置和重置函数周围的值。
  13: iload         4
  15: ldc           #5                  // int 65536
  17: if_icmpge     92
  20: aload_0
  21: getfield      #2                  // Field re:[D
  24: iload         4
  26: daload
  27: dstore        5
  29: aload_0
  30: getfield      #3                  // Field im:[D
  33: iload         4
  35: daload
  36: dstore        7
  38: aload_1
  39: getfield      #2                  // Field re:[D
  42: iload         4
  44: daload
  45: dstore        9
  47: aload_1
  48: getfield      #3                  // Field im:[D
  51: iload         4
  53: daload
  54: dstore        11
  56: aload_2
  57: iload         4
  59: dload         5
  61: dload         9
  63: dmul
  64: dload         7
  66: dload         11
  68: dmul
  69: dsub
  70: dastore
  71: aload_3
  72: iload         4
  74: dload         5
  76: dload         11
  78: dmul
  79: dload         9
  81: dload         7
  83: dmul
  84: dadd
  85: dastore
  86: iinc          4, 1
  89: goto          13
(set! *unchecked-math* :warn-on-boxed)

(def ^long ^:const size 65536)

(defn get-zero-complex-array []
  {:re (double-array size)
   :im (double-array size)})

(defn multiply-complex-arrays [a b]
  (let [a-re-array (doubles (get a :re))
        a-im-array (doubles (get a :im))
        b-re-array (doubles (get b :re))
        b-im-array (doubles (get b :im))
        res-re-array (double-array size)
        res-im-array (double-array size)
        s (long size)]
    (loop [i 0]
      (if (< i s)
        (let [a-re (aget a-re-array i)
              a-im (aget a-im-array i)
              b-re (aget b-re-array i)
              b-im (aget b-im-array i)]
          (aset res-re-array i (- (* a-re b-re) (* a-im b-im)))
          (aset res-im-array i (+ (* a-re b-im) (* b-re a-im)))
          (recur (inc i)))
        {:re res-re-array :im res-im-array}))))

(defn compute []
  (let [res (loop [i 0 a (get-zero-complex-array)]
              (if (< i 30000)
                (recur (inc i) (multiply-complex-arrays a a))
                a))]
    (aget (get res :re) 0)))