Is it possible to have Groovy NOT auto-box every single long I have in my application?
The following code ...
public class SumTest {
public static void main(String[] args) {
long[] longs = new long[100000000];
long nanoStart = System.nanoTime();
long counter = 1;
for (int i = 0; i < longs.length; i++) {
longs[i] = counter++;
}
double msPop = (System.nanoTime() - nanoStart) / 1000000d;
System.out.println("Time taken, population: " + msPop + "ms.");
nanoStart = System.nanoTime();
long sum = 0;
for (int i = 0; i < longs.length; i++) {
sum += longs[i];
}
double msSum = (System.nanoTime() - nanoStart) / 1000000d;
System.out.println("Time taken, sum: " + msSum + "ms, total: " + (msPop + msSum) + "ms");
System.out.println(" (sum: " + sum + ")");
}
}
... exhibits vastly different run times when renamed to '.groovy' from '.java':
Java:
Time taken, population: 94.793746ms.
Time taken, sum: 65.172605ms, total: 159.966351ms
(sum: 5000000050000000)
Groovy:
Time taken, population: 2233.995965ms.
Time taken, sum: 2203.64302ms, total: 4437.638985ms
(sum: 5000000050000000)
.. which is a ~30x difference.
The situation is compounded when I stick the long inside an object (as is the case in my real code):
public class SumTest {
static class Holder {
long l;
Holder(long l) { this.l = l; }
long getL() { return l; }
}
public static void main(String[] args) {
Holder[] longs = new Holder[100000000];
long nanoStart = System.nanoTime();
long counter = 1;
for (int i = 0; i < longs.length; i++) {
longs[i] = new Holder(counter++);
}
double msPop = (System.nanoTime() - nanoStart) / 1000000d;
System.out.println("Time taken, population: " + msPop + "ms.");
nanoStart = System.nanoTime();
long sum = 0;
for (int i = 0; i < longs.length; i++) {
sum += longs[i].getL();
}
double msSum = (System.nanoTime() - nanoStart) / 1000000d;
System.out.println("Time taken, sum: " + msSum + "ms, total: " + (msPop + msSum) + "ms");
System.out.println(" (sum: " + sum + ")");
}
}
Run times (note that I run with -Xms16384M -Xmx16384M here):
Java
Time taken, population: 1083.784927ms.
Time taken, sum: 180.518991ms, total: 1264.3039179999998ms
(sum: 5000000050000000)
Groovy:
Time taken, population: 9816.007447ms.
Time taken, sum: 8685.506864ms, total: 18501.514311ms
(sum: 5000000050000000)
.. which on the total is ~15 times faster, but the most important difference comes with actual use of these object (represented by the summing): ~50x.
Can this somehow be fixed? Can I coax Groovy to not autobox every single operation involving primitives, when the operations in question only concerns primitives and primitive operations?
(Wow! Strange how thoroughly formulating a question nearly instantly leads to an answer?!)
Fix: Write @CompileStatic
on top of the class.
Time taken, population: 1562.978726ms.
Time taken, sum: 183.388353ms, total: 1746.367079ms
(sum: 5000000050000000)