Performance Tipps: Loops

Artikel: ActionScript, Performance Tipps | 05.08.2007

In Action Script gibt es verschiedene Möglichkeiten Loops (Schleifen) zu realisieren, doch kaum jemand kennt die Performanceunterschiede zwischen den verschieden Möglichkeiten.
Ich werde hier auf die unterschiedliche Performance Unterschiede eingehen, auch können anhand von Beispiele diese nachvollzogen werden.

Inhalt

Übersicht der Schleifen Typen / Arten

Diese Übersicht der einzelnen Schleifen Typen/ Arten und deren Sinn und Zweck, soll helfen deren Arbeitsweise ein wenig genauer zu verstehen.

for-Schleifen

Die Schleife ist dafür gedacht wenn man genau weiß, wie oft eine Anweisung wiederholt werden soll. Sie sollte also verwendet werden wenn man Movieclips kopiert oder eine feste Anzahl von Objekten bewegen will.

Syntax:
for (init; condition; update) { // Anweisungen; }
Beispiel:
var i:Number; for (i = 0; i < 10; i++) { trace(i); }

for..in Schleifen

Diese Schleife wird verwendet wenn Unterobjekte eines Movieclips, Objekteigenschaften oder Array-Elemente durchsucht werden sollen. Man kann also auch ohne weiteres _level0.[MovieClip] verwenden um alle Elementes die sich im dem MovieClip befinden zu durchsuchen.

Syntax:
for (init; in object;) { // Anweisungen; }
Beispiel:
var myArray:Array = ["a", "b", "c", "d"]; // ... for (var i:String in myArray) { trace(myArray[i]); }

while Schleifen

Die while Schleife wird so lange ausgeführt solange die Bedingung wahr ist (true), sobald die Bedingung nicht mehr wahr ist (false) wird die Schleife verlassen. Diese Schleife ist also dazu gedacht wenn man nicht genau weiß wie viele Wiederholungen man benötigt bevor man sein Ziel erreicht hat.
Man sollte aber aufpassen das dies Bedingung auch zutreffen kann sonst erzeugt man eine Endlosschleife.

Syntax:
init; while (condition;) { // Anweisungen; update }
Beispiel:
var i:Number = 0; while (i < 10) { trace(i); i++; }

do..while Schleifen

Die do..while Schleife funktioniert genauso wie eine while Schleife mit dem Unterschied das der Code mindestens 1 mal ausgeführt wird, da die Bedingung erst am Ende geprüft wird.

Syntax:
init; do { // Anweisungen; update } while (condition;)
Beispiel:
var i:Number = 0; do { trace(i); i++; } while (i < 10)

Tipps im Umgang mit Schleifen / Loops

Tip #1 - Verwenden von Abbruch Bedingungen

Durch das verwenden von der richtigen Abbruch Bedingungen kann eine Schleife vorzeitig verlassen werden und es wird so eine menge Rechenzeit und Performance eingespart.
Wenn man eine Schleife bei jedem Frame ausführt um unbenutzte Objekte zu löschen oder andere Sachen zu machen, kann man sich auch überlegen ob die Schleife nicht nach dem ersten gefunden Object abbrechen sollte.
Angenommen die Schleife soll bei 15 Frames die Sekunde unbenutzte Objekte löschen und die Schleife läuft in jedem Frame.
Selbst wenn nach einem Object/Anweisung die Schleife verlassen wird, schafft man in 10 Sek 150 Objekte ( Framerate * Zeit ) zu löschen
Wenn es kein EGO-Shooter ist oder ein Actionspiel, wo wirklich so viele Objekte auf einen Schlag zu löschen sind, reicht das also voll aus.

In diesem Test wird eine Zufallszahl gesucht und sobald diese gefunden wird, wird die Schleife verlassen.
Was hier auffällt das die Schleifenzeit mal länger und mal kürzer ist je nachdem welche Zufallszahl gesucht wird. Eine guten Schleifenbedingung kann also eine Menge Rechenleistung und Performance einsparen.
Man sollte also darauf achten immer die Schleife so zu machen das Sie sich beendet nachdem Sie das Ergebnis gefunden hat.

Hier wird der direkte Schleifenabbruch durch die Schleifenbedingung und der Abbruch durch break; verglichen.
Was hier direkt auffällt das der Schleifenabbruch durch die Schleifenbedingung um einiges schneller ist, als der Abbruch mit break;. Man kann also eine Menge Zeit bei großen Schleifen sparen wenn man sich genau überlegt welche Abbruchbedingung man wählt.

Tip #2 - Sinnvoller Einsatz von Schleifen

Viele ActionScript Programmierer wissen leider nicht, das Schleifen im Vergleich zu einzelnen Aufrufen doch um einiges langsamer sind.
Wenn man also nur wenige Anweisungen durchführen muss, wie mehrere Zähler zu erhöhen oder sonstiges, sollte man auf Schleifen verzichten.

Mit Schleife:
var i1:Number = 100000; var a1:Array = [0,1,2]; while (i1>0) { for(var i=0;i<a1.length;i++) { a1[i]++; } i1--; }
Ohne Schleife:
var i2:Number = 100000; var a2:Array = [0,1,2]; while (i2>0) { a2[0]++; a2[1]++; a2[2]++; i2--; }

Hier werden die beiden Beispiele verglichen und was auffällt das durch den Verzicht der zusätzlichen Schleife eine Menge Performance eingespart werden kann.
Wenn man also nur weniger Sachen zu erledigen hat, sollte man sich überlegen ob man nicht auf eine zusätzliche Schleife verzichtet, auch wenn es mehr Tipparbeit ist.

Tip #3 - Anweisungen in Schleifen meiden, wenn diese auch außerhalb definiert werden können

Es sollte grundsätzlich vermieden werden eine Anweisung öfters als nötig auszuführen.
Soweit dies möglich ist, sollten Anweisungen und Berechnungen außerhalb einer Schleife verwendet werden.

Anweisung innerhalb der Schleife:
var ab1:Number; var i1:Number = 100000; var a1:String = "Hello World, Hello Flash, Hello Rei, Hello Markus,..."; while (i1>0) { ab1+=a1.length; i1--; }
Anweisung außerhalb der Schleife:
var ab2:Number; var i2:Number = 100000; var a2:String = "Hello World, Hello Flash, Hello Rei, Hello Markus,..."; var a2_length=a2.length; while (i2>0) { ab2+=a2_length; i2--; }

Der Test zeigt deutlich was eigentlich auch vorher klar sein sollte, das eine Anweisung innerhalb einer Schleife die mehrfach ausgerufen wird um einiges langsamer ist als wenn diese Anweisung nur 1 mal außerhalb der Schleife aufgerufen wird.

Tip 4# - .lenght und andere dynamische Schleifenbedingungen meiden

Der vorher gegangen Test zeigt klar das es schlauer ist, Anweisungen außerhalb einer Schleife zu definieren, das selbe trifft natürlich auch auf die Schleifenbedingung zu.
Soweit wie möglich sollten vorher die Bedingungen ausgerechnet werden und dann übergeben werden.

Anweisung innerhalb der Schleife:
var ab1:Number; var i1:Number = 100000; var a1:String = "Hello World, Hello Flash, Hello Rei, Hello Markus,..."; while (i1>a1.length) { ab1+=1; i1--; }
Anweisung außerhalb der Schleife:
var ab2:Number; var i2:Number = 100000; var a2:String = "Hello World, Hello Flash, Hello Rei, Hello Markus,..."; var a2_length=a2.length; while (i2>a2_length) { ab2+=1; i2--; }

Hier sieht man klar, das man so viel wie möglich statisch halten sollte damit die Schleife schnell abgearbeitet werden kann, dies ist aber nicht immer möglich.
Fall es möglich ist kann man sich hierdurch eine Menge Performance sparen, wie der Test zeigt.

Tip 5# - Inline Code verwenden, anstatt Funktionen

Durch die Verwendung von Inline Code kann auch einiges an Performance gespart werden.
Es ist ohne Frage übersichtlicher eine Funktion für eine Berechnung zu verwenden die öfters Verwendung findet, aber in Schleifen kann man sich dadurch sehr viel Performance sparen.

Funktion:
var ab1:Number = 1; var i1:Number = 100000; function testf1() { ab1+=(1/3); } while (i1>0) { testf1(); i1--; }
Inline Code:
var ab2:Number = 1; var i2:Number = 100000; while (i2>0) { ab2+=(1/3); i2--; }

Dieses Ergebnis hätte vielleicht nicht jeder erwartet, aber durch Inline Programmierung kann hier eine Menge Performance erzielt werden.
Das selbe gilt übrigens auch für a=functionsaufruf();, man sollte sich also überlegen ob man die Übersichtlichkeit von Funktionen gegen Performance von Inlinecode tauschen möchte.

Performance Unterschiede der verschiedenen Schleifen Typen

Anbei ein paar Test wie sich die unterschiedlichen Schleifen verhalten im Hinblick auf die Performance, auch habe ich natürlich die Verwendung der einzelnen Schleifen getestet für den Bereich für welchen diese eher nicht gedacht sind.

Was bei diesem Test auffallen sollte, es gibt zwischen der While Schleifen und For Schleifen kaum gravierende Geschwindkeitsunterschiede. Jedoch schneidet die Do While Schleife im Vergleich zu den anderen am schlechtesten ab ! Dies liegt daran das bei einer do..while Schleife programmiertechnisch mehr geprüft werden muss als bei einer normalen While Schleife.

Zusammenfassung

Es gibt bei einer sauberen und überlegten Programmierung nicht viele Möglichkeiten die Geschwindigkeit von Schleifen zu verbessern, man sollte aber auf jedenfalls Do While Schleifen meiden, da diese im Vergleich zu den anderen Schleifen am schlechtesten abgeschnitten haben.
Auch sollte man darauf achten eine gut überlegte Schleifenbedingung festzulegen wenn man z.b: nach was sucht, sollte die Schleife verlassen werden nachdem man es gefunden hat.
Man sollte sich auf überlegen ob es für 2-4 Anweisungen wirklich nötig ist eine zusätzliche Schleife zu verwenden.
Anweisungen sollten wenn möglich außerhalb der Schleife definiert werden, damit nicht unnötig Anweisungen wiederholt werden.
Verwenden von statischen Schleifenbediungen anstatt von dynamischen Schleifenbedingungen.