【发布时间】:2015-10-09 00:02:47
【问题描述】:
我试图弄清楚为什么此 Clojure 代码与其 Java 等效代码之间存在性能差异。 Clojure 代码:
(ns trigperf.core (:gen-class))
(deftype city [^String name ^double latr ^double lonr
^double sinlat ^double coslat ^double sinlon ^double coslon])
(defn dist [^city city1 ^city city2]
(let [st1 (double (.sinlat city1)) st2 (double (.sinlat city2))
ct1 (double (.coslat city1)) ct2 (double (.coslat city2))
ln1 (double (.lonr city1)) ln2 (double (.lonr city2))]
(Math/acos (+ (* st1 st2) (* ct1 ct2 (Math/cos (Math/abs (- ln1 ln2))))))))
(defn cost [route]
(reduce + (map dist route (drop 1 route))))
(defn test-data []
(take 100 (repeatedly
#(let [latr (/ (* (- (rand 180) 90) Math/PI) 180)
lonr (/ (* (- (rand 360) 180) Math/PI) 180)]
(city. "" latr lonr
(Math/sin latr) (Math/cos latr)
(Math/sin lonr) (Math/cos lonr))))))
(defn run-test []
(let [data (test-data)] (time (dotimes [i 99999] (cost data)))))
(defn -main [& args] (run-test))
Java 等价物:
public class City {
public String name;
public double latr;
public double lonr;
public double sinlat;
public double coslat;
public double sinlon;
public double coslon;
public City(String n, double a, double b, double c, double d, double e, double f) {
name = n; latr = a; lonr = b;
sinlat = c; coslat = d; sinlon = e; coslon = f;
}
}
public class Trigperf {
public static City[] test_data() {
City[] arr = new City[100];
for (int c=0; c < 100; ++c) {
double latr = (((Math.random() * 180) - 90) * Math.PI) / 180;
double lonr = (((Math.random() * 180) - 90) * Math.PI) / 180;
arr[c] = new City("", latr, lonr, Math.sin(latr), Math.cos(latr),
Math.sin(lonr), Math.cos(lonr));
}
return arr;
}
public static double dist(City city1, City city2) {
return Math.acos((city1.sinlat * city2.sinlat) +
(city1.coslat * city2.coslat *
(Math.cos (Math.abs (city1.lonr - city2.lonr)))));
}
public static double cost(City[] route) {
double acc = 0;
for (int c=0; c < route.length - 1; ++c) {
acc += dist(route[c], route[c + 1]);
}
return acc;
}
public static void run_test() {
City[] data = test_data();
long start = System.currentTimeMillis();
for (int c=0; c < 99999; ++c) { cost(data); }
long stop = System.currentTimeMillis();
System.out.format( "Elapsed: %dms\n", stop - start);
}
public static void main(String[] args) {
run_test();
}
}
运行 Clojure 代码大约需要 4 秒,运行 Java 版本大约需要 2 秒。所以 Clojure 需要两倍的时间。但是我已经在我能想到的所有地方都进行了类型提示,并确保没有反射警告。如何提高 Clojure 代码的速度以接近 Java 代码的速度?
【问题讨论】:
-
当您在 warn-on-reflection 设置为 true 的情况下运行时,它会在您加载文件时打印任何警告吗?
-
没有。正如我所说,我已经摆脱了所有反射警告。
-
对不起,我似乎并没有真正阅读整个问题。
标签: java performance clojure