Het leek me handig om een artikel te plaatsen met wat kleine performance tips.
Je performance in de gaten houden is een belangrijk onderdeel bij het maken van goede applicaties.
Bij de gemiddelde fotogallery of portfolio site is dit misschien niet zo’n big deal. Maar wanneer je met particles of games aan de slag gaat en je bepaalde code uitvoert in onEnterFrame handlers en veel door loops loopt, is het zeker de moeite waard om zo efficiënt mogelijk te programmeren.
Vaak zijn het kleine handigheidjes die je jezelf even aan moet wennen.
Als iemand toevoegingen heeft of onjuistheden opmerkt. Dan hoor ik het graag.
Math.max en Math.min zijn traag
Het gebruik van Math.max en Math.min is erg traag in vergelijking met een if statement.
1 2 3 4 5 6 7 8 9 10 11 | //In plaats van var v1:Number = 10; var v2:Number = 20; var v3:Number = Math.max(v1,v2); //prefereer ik (± 8.5x zo snel) var v1:Number = 10; var v2:Number = 20; var v3:Number = (v1 >= v2) ? v1 : v2; |
Math.abs is traag.
Het gebruik van Math.abs is erg traag in vergelijking met een if statement.
1 2 3 4 5 6 7 8 9 | //In plaats van var v1:Number = -10; var v2:Number = Math.abs(v1); //prefereer ik (± 7.5x zo snel) var v1:Number = -10; var v2:Number = (v1 < 0) ? -v1 : v1; |
Math.floor is trager dan casten naar int.
Je kunt Math.floor eenvoudig vermijden door te casten naar int.
1 2 3 4 5 6 7 8 | var v1:Number = 10.5; var v2:int; //In plaats van v2 = Math.floor(v1); //prefereer ik (± 3.5x zo snel) v2 = int(v1); |
Er is nog een snellere methode. Deze is wat minder leesbaar, maar 1.5x sneller dan de int(value) methode.
1 2 3 4 | var v1:Number = 10.5; var v2:int; v2 = v1>>0; |
Bovenstaande methodes werken alleen bij positieve getallen!
Als het getal ook negatief kan zijn moet je hier een check voor maken.
Dit is iets trager, maar nog steeds veel sneller dan Math.floor.
1 | v2 = (v1>0) ? v1 >>0 : (v1>>0)-1; |
Math.ceil is ook trager dan casten naar int.
Voor Math.ceil geldt eigenlijk hetzelfde als voor Math.floor.
Alleen kun je niet zomaar naar int casten en er 1 bij optellen:
Math.ceil(1.2) == 2;
int(1.2)+1 == 2;
Math.ceil(1) == 1;
int(1)+1 == 2;
Daarom gebruiken we een inline if statement.
1 2 3 4 5 6 7 8 | var v1:Number = 10.5; var v2:int; //In plaats van v2 = Math.ceil(v1); //prefereer ik (± 2.5x zo snel) v2 = (int(v1) == v1) ? v1 : int(v1) + 1; |
En de bitwise methode zoals bij Math.floor geeft hier zelfs nog iets meer winst dan bij Math.floor het geval is.
1 2 3 4 | var v1:Number = 10.5; var v2:int; v2 = (v1 >> 0 == v1) ? v1 : (v1 >> 0) + 1; |
Bovenstaande methodes werken alleen bij positieve getallen!
Als het getal ook negatief kan zijn moet je hier een check voor maken.
Dit is iets trager, maar nog steeds veel sneller dan Math.ceil.
1 | v2 = (v1 >> 0 == v1) ? v1 : (v1 < 0) ? (v1 >> 0) : (v1 >> 0) + 1; |
Vermenigvuldigen is sneller dan delen.
1 | 20 / 2 is ± 7% langzamer dan 20 * .5; |
Bitwise operations zijn super snel!
Het gebruik van bitwise operations kan je project een flinke performanceboost geven.
Deze zijn echt super snel mits ze gebruikt worden in combinatie met integers.
Als je Numbers gebruikt kun je zomaar voor verrassingen komen te staan.
1 2 3 4 5 6 | var v1:Number = 20; var v2:Number; v2 = v1 * .5; //is ± 1.4x zo snel als v2 = v1 >> 1; |
Maar als we integers gebruiken:
1 2 3 4 5 6 | var v1:int = 20; var v2: int; v2 = v1 >> 1; //is ± 1.6x zo snel als v2 = v1 * .5; |
Bitwise operations ronden je getallen wel af op hele getallen. Maar dat zie ik vaker als een voordeel dan een nadeel.
Bijvoorbeeld bij het uitlijnen van textfields. Je wilt textfields altijd op hele pixels plaatsen.
Vaak wil je een textfield in het midden van een knop zetten. Ik gebruik daarvoor de volgende code:
1 | _txt.x = width-_txt.width >> 1; |
Een aantal bitwise tricks die in je voordeel kunnen werken mits je ze gebruikt met integers:
1 2 3 4 5 6 7 8 9 10 11 | //delen door 2 value >> 1; // Vermenigvuldigen met 2 value < < 1; //positief/negatief omdraaien (± 1.2x zo snel) ~value + 1; // is gelijk aan: value * -1; //en is gelijk aan: -value //even/oneven controleren (value & 1) == 0; //is gelijk aan: (value % 2) == 0; |
Integers zijn sneller dan Numbers.
Sommige van de hierboven beschreven methode gaan uit van een bepaald datatype.
De behaalde resultaten kunnen namelijk nogal verschillen tussen bepaalde datatypen.
Voorbeeld:
1 2 3 4 5 6 | var v1:int = -11; var v2:int; //dit: v2 = v1*-1; //is sneller dan v2 = -v1; |
Maar, als je ditzelfde met Numbers doet:
1 2 3 4 5 6 7 | var v1:Number = -11; var v2: Number; //is dit ± 15% sneller: v2 = -v1; //dan: v2 = v1*-1; |
Over het algemeen zijn integers sneller.
Gebruik daarom ook altijd integers in loops en bij voorkeur uints als de loop optelt.
In flash player 9 was de performance van uints belachelijk slecht. In veel gevallen waren uints zelfs trager dan Numbers.
Hierom kozen veel developers voor ints als loop counter. Ik ben hier eigenlijk nooit in mee gegaan, omdat het meer sense maakt om uints te gebruiken in een positie loop. Daar zijn ze immers voor.
Gelukkig is de performance van uints in flash player 10 zoals deze moet zijn. (hetzelfde of zelfs iets sneller dan ints)
loop voorbeeld:
1 2 3 4 5 | for(var i:uint = 0; i<100; i++) //ipv for(var i:int = 0; i<100; i++) //en ipv for(var i:Number = 0; i<100; i++) |
Als je loop counter negatief kan worden gebruik je natuurlijk ints.
Gebruik geen array.push als dit niet nodig is.
1 2 3 4 5 | var arr:Array = []; for(var a:uint = 0; a < 10000000; a++) { arr[a] = a ; } |
is eens zo snel als:
1 2 3 4 5 | var arr:Array = []; for(var a:uint = 0; a < 10000000; a++) { arr.push(a); } |
Gebruik Vectors waar je maar kunt.
1 2 3 4 5 6 | var arr:Vector.<uint> = new Vector.<uint>(); for(var a:uint = 0; a < 10000000; a++) { arr[a] = a ; } |
is eens zo snel als:
1 2 3 4 5 6 | var arr:Array = []; for(var a:uint = 0; a < 10000000; a++) { arr[a] = a; } |
Sla de length van je array/vector op in een variable voor je gaat loopen.
1 2 3 4 5 | var l:Number = arr.length; for (var i:uint = 0; i < l; i++ ) { v2 = arr[i]; } |
is 5x! sneller dan:
1 2 3 4 | for (var i:uint = 0; i < arr.length; i++ ) { v2 = arr[i]; } |
De ‘one dot’ regel.
Als je meerdere keren een property aan wilt spreken waar je meer dan één . voor nodig hebt, sla hem dan op in een lokale variable.
Voorbeeld:
1 2 3 4 5 6 7 8 9 10 11 | var mc:MovieClip = new MovieClip(); mc.data = {}; mc.data.x = 10; var value:Number; var prop:Number = mc.data.x; for(var a:uint = 0; a < 10000000; a++) { value = prop; } |
is 10x! zo snel als:
1 2 3 4 5 6 7 8 9 10 | var mc:MovieClip = new MovieClip(); mc.data = {}; mc.data.x = 10; var value:Number; for(var a:uint = 0; a < 10000000; a++) { value = mc.data.x; } |
Gebruik de ternary operator.
De ternary operator is niet zozeer sneller dan een ‘normaal’ if statement, maar het maakt je code wel een stuk compacter en leesbaarder. Let wel op dat je het condition gedeelte altijd tussen ( ) zet. Doe je dit niet werkt je code prima, geen error aan de lucht. Maar het is 10% langzamer dan wanneer het condintion gedeelte tussen ( ) staat.
Dus:
1 2 3 | result = (value1==value2) ? x : y; //ipv result = value1==value2 ? x : y; |
1 2 3 4 5 6 | var v1:Number = -10; var v2:Number; //dit: v2 = (v1 < 0) ? -v1 : v1; // is iets langzamer dan: (v1 < 0) ? v2 = -v1 : v2 = v1; |
In het bovenstaande voorbeeld gebruik ik persoonlijk altijd de langzamere methode.
We praten hier over een paar milliseconden op 10000000 checks. En ik vind de eerste methode een stuk leesbaarder.
Nog een lijstje met tips:
* Gebruik een zo strikt mogelijk datatype.
* Enterframes zijn sneller dan timers.
* Gebruik zo min mogelijk enterframe handlers en/of timer handlers.
* Constanten zijn sneller dan variablen.
* Zet geen ‘zware’ code in je constructors. Maak liever een init functie die je aanroept in je constructor.
* Callbacks meegeven is sneller dan events dispatchen.
* Test zelf hoe bepaalde optimalisaties uitpakken in jouw project.
* Draaf niet te ver door met optimaliseren. Een paar milliseconden winst in ruil voor een moeilijk leesbare code zou ik niet aan willen raden.
Stellingen in bovenstaand document zijn gebaseerd op testresultaten behaald met de flash 10.1 IDE player van CS5 op Windows Vista 64bit.
Vooral in flash player 9 kunnen de resultaten nog wel eens anders uitpakken. Test daarom altijd zelf en neem niet zomaar aan wat je op internet leest.

Na de aanschaf van een Wacom Bamboo heb ik de smaak van het foto-bewerken weer helemaal te pakken.