Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy for loop execution time

Tags:

groovy

O Groovy Gurus,

This code snippet runs in around 1 second

    for (int i in (1..10000000)) {
         j = i;
    }

while this one takes almost 9 second

    for (int i = 1; i < 10000000; i++) {
         j = i;
    }

Why is it so?

like image 872
rest_day Avatar asked May 28 '09 12:05

rest_day


3 Answers

Ok. Here is my take on why?

If you convert both scripts to bytecode, you will notice that

  1. ForInLoop uses Range. Iterator is used to advance during each loop. Comparison (<) is made directly to int (or Integer) to determine whether the exit condition has been met or not
  2. ForLoop uses traditional increment, check condition, and perform action. For checking condition i < 10000000 it uses Groovy's ScriptBytecodeAdapter.compareLessThan. If you dig deep into that method's code, you will find both sides of comparison is taken in as Object and there are so many things going on, casting, comparing them as object, etc.

ScriptBytecodeAdapter.compareLessThan --> ScriptBytecodeAdapter.compareTo --> DefaultTypeTransformation.compareTo

There are other classes in typehandling package which implements compareTo method specifically for math data types, not sure why they are not being used, (if they are not being used)

I am suspecting that is the reason second loop is taking longer. Again, please correct me if I am wrong or missing something...

like image 59
Kartik Shah Avatar answered Oct 14 '22 07:10

Kartik Shah


In your testing, be sure to "warm" the JVM up before taking the measure, otherwise you may wind up triggering various startup actions in the platform (class loading, JIT compilation). Run your tests many times in a row too. Also, if you did the second test while a garbage collect was going on, that might have an impact. Try running each of your tests 100 times and print out the times after each test, and see what that tells you.

like image 2
Jim Ferrans Avatar answered Oct 14 '22 08:10

Jim Ferrans


If you can eliminate potential artifacts from startup time as Jim suggests, then I'd hazard a guess that the Java-style for loop in Groovy is not so well implemented as the original Groovy-style for loop. It was only added as of v1.5 after user requests, so perhaps its implementation was a bit of an afterthought.

Have you taken a look at the bytecode generated for your two examples to see if there are any differences? There was a discussion about Groovy performance here in which one of the comments (from one 'johnchase') says this:

I wonder if the difference you saw related to how Groovy uses numbers (primitives) - since it wraps all primitives in their equivalent Java wrapper classes (int -> Integer), I’d imagine that would slow things down quite a bit. I’d be interested in seeing the performance of Java code that loops 10,000,000 using the wrapper classes instead of ints.

So perhaps the original Groovy for loop does not suffer from this? Just speculation on my part really though.

like image 1
Xiaofu Avatar answered Oct 14 '22 09:10

Xiaofu