Notes: Loop Optimizations

Tuesday, January 27th, 2009 | Notes

Here is some testing I did to determine the best kind of loop to use in AS3. In the end the fastest I determined was a simple reverse while loop. Below is the results with the code for my testing beneath that. Where I could, I tried to run 1 million items in the collection. If I was unable to do that (the program would crash) I would run 500k items. From what I have learned, using the Array.forEach() is kinda expensive for what it does. Standard for() loops aren’t too bad, but the for…in() loops are even worse than the Array.forEach(). If you know of anything faster methods or maybe I tested incorrectly please let me know!


Standard Loops (1 Million runs)
test00(); for() [uint inline & list.length] 198ms, 204ms, 204ms
test0(); for() [uint & list.length] 150ms, 157ms, 157ms
test1(); for() [uint & l] 149ms, 140ms, 145ms
test2(); for() [uint & l reverse] 149ms, 140ms, 145ms
test3(); for each in() 160ms, 163ms, 164ms
test4(); for in() 583ms, 585ms, 586ms
test5(); while() [i < l] 139ms, 145ms, 142ms
test6(); while() [i--] 139ms, 144ms, 143ms
test7(); while() [i-- > 0] 152ms, 154ms, 154ms
test8(); do while() 234ms, 236ms, 237ms
test18(); Array.forEach() 324ms, 326ms, 321ms


Dictionary Loops (500k runs)
test9(); Dictionary for each in() [local vars] 90ms, 89ms, 90ms
test10(); Dictionary for each in() 87ms, 88ms, 88ms
test11(); Dictionary for each in() [inline] 88ms, 88ms, 87ms


Object Loops (500k runs)
test12(); Object for each in() [local vars] 93ms, 90ms, 92ms
test13(); Object for each in() 96ms, 93ms, 90ms
test14(); Object for each in() [inline] 98ms, 94ms, 91ms


Dictionary Loops with ‘length’ variable (1 Million and 500k runs)
test15(); Dictionary while() [i < l] 1M 144ms, 142ms, 136ms / 500k 72ms, 70ms, 71ms
test16(); Dictionary while() [i--] 1M 138ms, 138ms, 141ms / 500k 74ms, 70ms, 70ms
test17(); Dictionary while() [i-- > 0] 1M 153ms, 147ms, 149ms / 500k 74ms, 74ms, 75ms


package {

	import flash.display.MovieClip;
	import flash.utils.getTimer;
	import flash.utils.Dictionary;

	public class LoopTest extends MovieClip {
		private var l:int;
		private var list:Array = new Array();
		private var dict:Dictionary = new Dictionary();
		private var obj:Object = new Object();

		public function LoopTest() {
			var i:uint;

			//Create the source array
			for(i = 0; i < 1000000; i++) {
				list.push(Math.random());
			}
			l = list.length;
			trace("List of " + l + " elements.");

			// Create the source dictionary
			/*for (i = 0; i < 500000; i++) {
				var n:Number = Math.random();
				dict[n] = n;
			}*/

			// Create the source object
			/*for (i = 0; i < 500000; i++) {
				var n:Number = Math.random();
				obj[n] = n;
			}*/

			// Create the source dictionary 2
			/*for (i = 0; i <= 500000; i++) {
				dict[i] = Math.random();
				dict["length"] = i;
			}
			trace("Dictionary of " + dict["length"] + " elements.");*/
		}

		public function test000():void {
			var ts:Number = getTimer();
			for(var i:Number = 0; i < list.length; i++) {
				var z:Number = Math.random();
			}
			trace("for() [Number &amp; list.length]: " + (getTimer() - ts) + "ms");
		}

		public function test00():void {
			var ts:Number = getTimer();
			for(var i:uint = 0; i < list.length; i++) {
				var z:Number = Math.random();
			}
			trace("for() [uint inline &amp; list.length]: " + (getTimer() - ts) + "ms");
		}

		public function test0():void {
			var ts:Number = getTimer();
			var i:uint;
			for(i = 0; i < list.length; i++) {
				var z:Number = Math.random();
			}
			trace("for() [uint &amp; list.length]: " + (getTimer() - ts) + "ms");
		}

		public function test1():void {
			var ts:Number = getTimer();
			var i:uint;
			for(i = 0; i < l; i++) {
				var z:Number = Math.random();
			}
			trace("for() [uint &amp; l]: " + (getTimer() - ts) + "ms");
		}

		public function test2():void {
			var ts:Number = getTimer();
			var i:int;
			var l2:int = l - 1;
			for(i = l2; i >= 0; i--) {
				var z:Number = Math.random();
			}
			trace("for() [uint &amp; l reverse]: " + (getTimer() - ts) + "ms");
		}

		public function test3():void {
			var ts:Number = getTimer();
			var j:Number;
			for each(j in list) {
				var z:Number = Math.random();
			}
			trace("for each in(): " + (getTimer() - ts) + "ms");
		}

		public function test4():void {
			var ts:Number = getTimer();
			var m:String;
			for (m in list) {
				var z:Number = Math.random();
			}
			trace("for in(): " + (getTimer() - ts) + "ms");
		}

		public function test5():void {
			var ts:Number = getTimer();
			var i:int = 0;
			while(i < l) {
				var z:Number = Math.random();
				i++;
			}
			trace("while() [i < l]: "+(getTimer()-ts)+"ms");
		}

		public function test6():void {
			var ts:Number = getTimer();
			var i:int = l - 1;
			while(i--) {
				var z:Number = Math.random();
			}
			trace("while() [i--]: "+(getTimer()-ts)+"ms");
		}

		public function test7():void {
			var ts:Number = getTimer();
			var i:uint = l;
			while( i-- > 0 ){
				var z:Number = Math.random();
			}
			trace("while() [i-- > 0]: "+(getTimer()-ts)+"ms");
		}

		public function test8():void {
			var ts:Number = getTimer();
			var i:int = l - 1;
			do {
				var z:Number = Math.random();
			} while (i--);
			trace("do while(): "+(getTimer()-ts)+"ms");
		}

		public function test18():void {
			var ts:Number = getTimer();
			list.forEach(doRandom);
			trace("Array.forEach(): "+(getTimer()-ts)+"ms");
		}

		private function doRandom(item:*, index:int, arr:Array):void {
            var z:Number = Math.random();
        }

		// Dictionary Tests

		public function test9():void {
			var ts:Number = getTimer();
			var d:Dictionary = dict, e:Object;
			for each (e in d) {
				var z:Number = Math.random();
			}
			trace("Dictionary for each in() [local vars]: "+(getTimer()-ts)+"ms");
		}

		public function test10():void {
			var ts:Number = getTimer();
			var e:Object;
			for each (e in dict) {
				var z:Number = Math.random();
			}
			trace("Dictionary for each in(): "+(getTimer()-ts)+"ms");
		}

		public function test11():void {
			var ts:Number = getTimer();
			for each (var e:Object in dict) {
				var z:Number = Math.random();
			}
			trace("Dictionary for each in() [inline]: "+(getTimer()-ts)+"ms");
		}

		// Object Tests

		public function test12():void {
			var ts:Number = getTimer();
			var o:Object = obj, e:Object;
			for each (e in o) {
				var z:Number = Math.random();
			}
			trace("Object for each in() [local vars]: "+(getTimer()-ts)+"ms");
		}

		public function test13():void {
			var ts:Number = getTimer();
			var e:Object;
			for each (e in obj) {
				var z:Number = Math.random();
			}
			trace("Object for each in(): "+(getTimer()-ts)+"ms");
		}

		public function test14():void {
			var ts:Number = getTimer();
			for each (var e:Object in obj) {
				var z:Number = Math.random();
			}
			trace("Object for each in() [inline]: "+(getTimer()-ts)+"ms");
		}

		// Dictionary Tests 2

		public function test15():void {
			var ts:Number = getTimer();
			var i:int = 0;
			var l:int = dict["length"];
			while(i < l) {
				var z:Number = Math.random();
				i++;
			}
			trace("dictionary while() [i < l]: "+(getTimer()-ts)+"ms");
		}

		public function test16():void {
			var ts:Number = getTimer();
			var i:int = dict["length"] - 1;
			while(i--) {
				var z:Number = Math.random();
			}
			trace("dictionary while() [i--]: "+(getTimer()-ts)+"ms");
		}

		public function test17():void {
			var ts:Number = getTimer();
			var i:uint = dict["length"];
			while( i-- > 0 ){
				var z:Number = Math.random();
			}
			trace("dictionary while() [i-- > 0]: "+(getTimer()-ts)+"ms");
		}
	}
}

Tags: ,

1 Comment to Notes: Loop Optimizations

[...] Notes: Loop Optimizations 2 Tuesday, September 8th, 2009 | Notes [...]

Leave a comment

Please upgrade your Flash Player To submit a comment, you must have Flash Player 9.0.0 or higher installed. I use a flash form here to help prevent spam.

Search

Categories