views:

1393

answers:

2

Is there a performance hit when iterating over object attributes vs. iterating an array?

Example, using objects:

var x:Object = {one: 1, two: 2, three: 3};
for (var s:String in x) {
 trace(x[s]);
}

Vs using an array

var a:Array = [1, 2, 3];
var len:Number = a.length;
for (var i:Number = 0; i < len; ++i) {
 trace(a[i]);
}

So - which is faster and most importantly by what factor?

IIRC, in some JavaScript implementation iterating over objects attributes is slower up to 20x but I haven't been able to find such measurement for ActionScript2.

A: 

OK. Why not do some simple measurements?

var time : Number;

time = getTimer();

var x:Object = {one: 1, two: 2, three: 3};

for( i = 0; i < 100000; i++ )
{
    for (var s:String in x) 
    {
     // lets not trace but do a simple assignment instead. 
     x[s] = x[s];
    }
}

trace( getTimer() - time + "ms");

time = getTimer();

var a:Array = [1, 2, 3];
var len:Number = a.length;

for( i = 0; i < 100000; i++ )
{
    for ( var j : Number = 0; j < len; j++) 
    {
     a[j] = a[j];
    }
}

trace( getTimer() - time + "ms");

On my machine the array iteration is somewhat slower. This could be because ActionScript 2 doesn't have 'real' arrays but only associative arrays (maps). Apparently to work with an array the compiler has to generate some code overhead. I haven't looked into the specifics of this but I can imagine that that could be the case.

BTW. Doing this test might also show that putting the array length value into a variable doesn't really increase performance either. Just give it go....

UPDATE: Even though ActionScript and JavaScript are syntactically related, the underlying execution mechanism is completely different. E.g. FireFox uses SpiderMonkey and IE will probably use a Microsoft implementation whereas AS2 is executed by the Adobe's AVM1.

Luke
not sure why you do the same test 100000 times? Also, as Simon remarked correctly, initialization should be kept out of the measurement...
moritzstefaner
+1  A: 

I just tried a very similar test, but iterating just once over 200k elements, with opposite results:

Task build-arr: 2221ms
Task iter-arr: 516ms

Task build-obj: 1410ms
Task iter-obj: 953ms

I suspect Luke's test is dominated by loop overhead, which seems bigger in the array case. Also, note that the array took significantly longer to populate in the first place, so ymmv if your task is insert-heavy.

Also, in my test, storing arr.length in a local variable gave a measurable performance increase of about 15%.

Update:

By popular demand, I am posting the code I used.

var iter:Number = 200000;
var time:Number = 0;
var obj:Object = {};
var arr:Array = [];

time = getTimer();
for (var i:Number = 0; i < iter; ++i) {
  arr[i] = i;
}
trace("Task build-arr: " + (getTimer() - time) + "ms");

time = getTimer();
for (var i:Number = 0; i < iter; ++i) {
  arr[i] = arr[i];
}
trace("Task iter-arr: " + (getTimer() - time) + "ms");

time = getTimer();
for (var i:Number = 0; i < iter; ++i) {
  obj[String(i)] = i;
}
trace("Task build-obj: " + (getTimer() - time) + "ms");

time = getTimer();
for (var i:String in obj) {
  obj[i] = obj[i];
}
trace("Task iter-obj: " + (getTimer() - time) + "ms");
Can you post your code?
Luke