For VS Foreach on Array performance (in AS3/Flex)

44,964

Solution 1

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. ;)

Solution 2

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

Solution 3

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

Solution 4

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 :-)

Share:
44,964
oshyshko
Author by

oshyshko

Updated on October 01, 2020

Comments

  • oshyshko
    oshyshko over 3 years

    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) {
        // ...
    }
    
  • Unreality
    Unreality almost 15 years
    he's asking as3, not .net framework. Different language execute the codes differently
  • Tyler Egeto
    Tyler Egeto almost 15 years
    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.
  • user3953201
    user3953201 almost 15 years
    @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.
  • geraldalewis
    geraldalewis almost 15 years
    for each is faster in AS3 than for - give it a benchmark if you'd like.
  • user3953201
    user3953201 almost 15 years
    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 ;-)
  • fenomas
    fenomas almost 15 years
    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
    fenomas almost 15 years
    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 almost 15 years
    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.
  • Juan Pablo Califano
    Juan Pablo Califano almost 15 years
    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.
  • oshyshko
    oshyshko almost 15 years
    @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:Number 2) 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: 750ms BTW: how do you think, why reverse is better? Is it because "i>=0" may be faster than "i<size"?
  • fenomas
    fenomas almost 15 years
    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. ;)
  • Juan Pablo Califano
    Juan Pablo Califano almost 15 years
    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 Pablo Califano almost 15 years
    @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
    Juan Pablo Califano almost 15 years
    + 1. I think you're right about this, even though some people seem to disagree (Haven't read your blog though).
  • fenomas
    fenomas almost 15 years
    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.
  • Juan Pablo Califano
    Juan Pablo Califano almost 15 years
    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.
  • fenomas
    fenomas almost 15 years
    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
    fenomas almost 15 years
    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
    fenomas almost 15 years
    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
    fenomas almost 15 years
    Juan: for..each was still slower with o typed as Number or int, so I'm not sure what you mean.
  • Mark Knol
    Mark Knol over 11 years
    Is this benchmarked as release build in a release FlashPlayer? How do you see the traces? Most users have the release player, and developers should uncheck 'permit debugging' in the publish settings. BTW I found jacksondunstan.com/articles/1978 a good resource for indepth benchmarks.