views:

5253

answers:

7

Which one is faster? Why?

var messages:Array = [.....]

// 1 - for
var len:int = messages.length;
for (var i:int = 0; i < len; i++) {
    var o:Object = messages[i];
    // ...
}

// 2 - foreach
for each (var o:Object in messages) {
    // ...
}
+1  A: 

for would be faster for arrays...but depending on the situation it can be foreach that is best...see this .net benchmark test.

Personally, I'd use either until I got to the point where it became necessary for me to optimize the code. Premature optimization is wasteful :-)

mezoid
he's asking as3, not .net framework. Different language execute the codes differently
Unreality
But the advice is still correct.
le dorfier
He's still correct however, in AS3, for loops are quite a bit faster that for each loops. This is because for loop's are a direct reference.
Tyler Egeto
@Unreality Yeah, I was aware when I posted my answer that he was asking for as3 rather than .net but I felt the bench mark test (for which I couldn't find one for as3 specifically) was fairly indicative of the general performance of any for/foreach loop.
mezoid
`for each` is faster in AS3 than `for` - give it a benchmark if you'd like.
Tyler: I disagree, from a quick test it looks like his for each loop is only faster because it doesn't contain any variable assignment. See the sample code in my answer.
fenomas
@fenomas: it does contain an explicit / Actionscript assignment, but you can access each array's item. That's probably the "only reason", rigth, but taking the assigment out makes the comparison unfair.
Juan Pablo Califano
A: 

sorry to prove you guys wrong, but for each is faster. even a lot. except, if you don't want to access the array values, but a) this does not make sense and b) this is not the case here.

as a result of this, i made a detailed post on my super new blog ... :D

back2dos
prove who wrong? this site isn't about proving people wrong, its about providing people with correct answers as voted by your peers. If my answer is not helpful then it won't be upvoted. I have no problems with that. Concerning your answer, though, it would be nice if you gave more proof than your own blog post...otherwise it seems about as reliable as editing wikipedia articles in your favor ;-)
mezoid
I don't buy these results. You're doing a variable assignment in your for loops, compared to an increment in the for each. To compare the loops, you should do an assignment in the for each loop as well, and if you do that, the results reverse. (The lesson of which, incidentally, is that the performance difference between the loop styles is small compared to a single variable assignment, and thus pretty trivial.)
fenomas
Now I know whose blog NOT to read...
musicfreak
+ 1. I think you're right about this, even though some people seem to disagree (Haven't read your blog though).
Juan Pablo Califano
+4  A: 

From where I'm sitting, regular for loops are moderately faster than for each loops in the minimal case. Also, as with AS2 days, decrementing your way through a for loop generally provides a very minor improvement.

But really, any slight difference here will be dwarfed by the requirements of what you actually do inside the loop. You can find operations that will work faster or slower in either case. The real answer is that neither kind of loop can be meaningfully said to be faster than the other - you must profile your code as it appears in your application.

Sample code:

var size:Number = 10000000;
var arr:Array = [];
for (var i:int=0; i<size; i++) { arr[i] = i; }
var time:Number, o:Object;

// for()
time = getTimer();
for (i=0; i<size; i++) { arr[i]; }
trace("for test: "+(getTimer()-time)+"ms");

// for() reversed
time = getTimer();
for (i=size-1; i>=0; i--) { arr[i]; }
trace("for reversed test: "+(getTimer()-time)+"ms");

// for..in
time = getTimer();
for each(o in arr) { o; }
trace("for each test: "+(getTimer()-time)+"ms");

Results:

for test: 124ms
for reversed test: 110ms
for each test: 261ms

Edit: To improve the comparison, I changed the inner loops so they do nothing but access the collection value.

Edit 2: Answers to oshyshko's comment:

  1. The compiler could skip the accesses in my internal loops, but it doesn't. The loops would exit two or three times faster if it was.
  2. The results change in the sample code you posted because in that version, the for loop now has an implicit type conversion. I left assignments out of my loops to avoid that. Of course one could argue that it's okay to have an extra cast in the for loop because "real code" would need it anyway, but to me that's just another way of saying "there's no general answer; which loop is faster depends on what you do inside your loop". Which is the answer I'm giving you. ;)
fenomas
@fenomas arr[i] may be skipped by interpreter becase the result is ignored. Also make value type strict: "o:Object" -> "o:Number".Try this:1) var time:Number, o:Number, v:Number2) replace "arr[i]" -> "v = arr[i]"3) // for..in time = getTimer(); for each(o in arr) { v = o; } trace("for each test: "+(getTimer()-time)+"ms");My results with Player 10:[trace] for test: 895ms[trace] for reversed test: 565ms[trace] for each test: 750msBTW: how do you think, why reverse is better?Is it because "i>=0" may be faster than "i<size"?
oshyshko
oshyshko, see my edit. For why decrementing is faster, I assume it's because + has an internal type check since it can apply to strings as well as numbers, and ++ inherits that. But considering it adds only a few ms over 10M iterations, I probably shouldn't have even mentioned it. It's the kind of thing people are probably better off not knowing. ;)
fenomas
Why did this get a downvote?
musicfreak
fenomas: I think that by removing the item access, you're missing the whole point. With a foreach you don't have to do the assignment in Actionscript (which is slower), yet you're able to access each item in the Array (and in a typed fashion). With a for loop you have to do this manually. The OP asked about loop performance on Arrays, and I think if you loop over an Array, you're doing it to access the elements it contains. So, I definitely think the assigment in the for loop should be there.
Juan Pablo Califano
Juan: I didn't remove the item access; all the loops in my example contain one access. I removed a variable assignment, which may be necessary in some loops and unnecessary in others.
fenomas
fenomas: Fair enough, you're right; access does not neccesarily means assignment. I think your typing the variable as Object as opposed to Number or int, for example, makes a difference.
Juan Pablo Califano
Juan: for..each was still slower with o typed as Number or int, so I'm not sure what you mean.
fenomas
+1  A: 

When iterating over an array, for each loops are way faster in my tests.

var len:int = 1000000;
var i:int = 0;
var arr:Array = [];

while(i < len) {
    arr[i] = i;
    i++;
}

function forEachLoop():void {
    var t:Number = getTimer();
    var sum:Number = 0;
    for each(var num:Number in arr) {
     sum += num;
    }
    trace("forEachLoop :", (getTimer() - t));
}

function whileLoop():void {
    var t:Number = getTimer();
    var sum:Number = 0;
    var i:int = 0;
    while(i < len) {
     sum += arr[i] as Number;    
     i++;
    }
    trace("whileLoop :", (getTimer() - t));
}

forEachLoop();
whileLoop();

This gives:

forEachLoop : 87 whileLoop : 967

Here, probably most of while loop time is spent casting the array item to a Number. However, I consider it a fair comparison, since that's what you get in the for each loop.

My guess is that this difference has to do with the fact that, as mentioned, the as operator is relatively expensive and array access is also relatively slow. With a for each loop, both operations are handled natively, I think, as opossed to performed in Actionscript.

Note, however, that if type conversion actually takes place, the for each version is much slower and the while version if noticeably faster (though, still, for each beats while):

To test, change array initialization to this:

while(i < len) {
    arr[i] = i + "";
    i++;
}

And now the results are:

forEachLoop : 328 whileLoop : 366

forEachLoop : 324 whileLoop : 369

Juan Pablo Califano
Uh, this code doesn't compares which kind of loop is faster; the performance of what is done inside each loop clearly dwarfs the difference between the style of the loops themselves. The lesson, of course, being that which loop is faster depends on what you do in it. Also, change your while() loop to a for() loop and it will speed up considerably. No idea why, presumably internal optimizations.
fenomas
Regarding while/for loops, about a year ago I posted the dissambled bytecode of both loops in flashcoders' list showing there was almost no difference. (I can repost them if you whish). More importantly, benchmarks showed no significant difference. So, I doubt using a for loop instead of a while loop will make any difference. Anyway, I changed the code to use a for loop, and even got rid of the "as" operator. Still, the for each version takes 57 ms vs 679 ms of the for loop. I agree that most of the time is spent in the body of the loop. Yet, everything else being equal, for each runs faster.
Juan Pablo Califano
Juan, I agree that there are cases where for..each is faster. There are also cases where it is not. What I'm saying is two things: First, in the most minimal cases, the for loop is faster, so if either sort can be said to be "intrinsically" faster, it's the for loop. Second, in non-minimal cases, which loop is faster depends on the body of the loop. Hence, there is no general case answer.
fenomas
Ah, two other notes. First, I definitely take back what I said about for() being faster than while(), that was my mistake. Second, if you still think your example code here is a good general case, try removing the "as" operator, and then change the "+=" operators in your loops to "-=" operators. The while loop will now be considerably faster, implying that your results are dominated by the internal type check of the + operator, not the natures of the loops themselves.
fenomas
Well, could be. Didn't check with -= (I did check removing "as"). Anyway, I agree that in some cases a for loop could be faster as your samples show. More importantly, as I think we both have agreed, the bottleneck in most "real-world" loops will be its body, not the loop mechanism; and in most real cases, you'd not iterate over 10000000 items. I tended to use while (or for) loops almost exclusively, but when I realized for each were not significantly slower in most cases I tested (and were faster in many of them), and also more readable and terse (at least to me), I switched to for each.
Juan Pablo Califano
+1  A: 

Hi there,

I've had this discussion with a few collegues before, and we have all found different results for different scenarios. However, there was one test that I found quite eloquent for comparison's sake:

var array:Array=new Array();
for (var k:uint=0; k<1000000; k++) {
    array.push(Math.random());
}

stage.addEventListener("mouseDown",foreachloop);
stage.addEventListener("mouseUp",forloop);

/////// Array /////

/* 49ms */
function foreachloop(e) {
    var t1:uint=getTimer();
    var tmp:Number=0;
    var i:uint=0;
    for each (var n:Number in array) {
     i++;
     tmp+=n;
    }
    trace("foreach", i, tmp, getTimer() - t1);
}
/***** 81ms  ****/
function forloop(e) {
    var t1:uint=getTimer();
    var tmp:Number=0;
    var l:uint=array.length;
    for(var i:uint = 0; i < l; i++)
     tmp += Number(array[i]);
    trace("for", i, tmp, getTimer() - t1);
}

What I like about this tests is that you have a reference for both the key and value in each iteration of both loops (removing the key counter in the "for-each" loop is not that relevant). Also, it operates with Number, which is probably the most common loop that you will want to optimize that much. And most importantly, the winner is the "for-each", which is my favorite loop :P

Notes:

-Referencing the array in a local variable within the function of the "for-each" loop is irrelevant, but in the "for" loop you do get a speed bump (75ms instead of 105ms):

function forloop(e) {
    var t1:uint=getTimer();
    var tmp:Number=0;
    var a:Array=array;
    var l:uint=a.length;
    for(var i:uint = 0; i < l; i++)
     tmp += Number(a[i]);
    trace("for", i, tmp, getTimer() - t1);
}

-If you run the same tests with the Vector class, the results are a bit confusing :S

Cay
As with Juan's answer, it's worth noting that if you remove the Number() cast and sum the values negatively (with -= instead of +=), the for loop comes out faster. Of course I understand the reasoning behind putting in the Number() cast, since you get it for free with for..each, but then again I can't think of a case where the code would work differently with the cast than without it...
fenomas
A: 

Just an add-on:

a for each...in loop doesn't assure You, that the elements in the array/vector gets enumerated in the ORDER THEY ARE STORED in them. (except XMLs) This IS a vital difference, IMO.

"...Therefore, you should not write code that depends on a for- each-in or for-in loop’s enumeration order unless you are processing XML data..." C.Moock

(i hope not to break law stating this one phrase...)

Happy benchmarking.

dbam
A: 

Maybe in a array where all element are there and start at zero (0 to X) it would be faster to use a for loop. In all other case (sparse array) it can be a LOT faster to use for each. The reason is the usage of two data structure in the array: Hast table an Debse Array. Please read my Array analysis using Tamarin source: http://jpauclair.wordpress.com/2009/12/02/tamarin-part-i-as3-array/

The for loop will check at undefined index where the for each will skip those one jumping to next element in the HastTable

jpauclair