Optimierung

Optimierung

> LeekScript-Tutorial

Hier werden wir über Optimierung sprechen, das Ziel der Optimierung ist es, die Leistung eines Algorithmus zu verbessern. Wenn wir von Optimierung sprechen, sprechen wir im Allgemeinen von Ausführungszeit, wobei das Ziel darin besteht, die Zeit zu reduzieren, die zum Ausführen einer Reihe von Anweisungen erforderlich ist.

In LeekScript wird diese Ausführungszeit durch eine Zahl geschätzt: die Anzahl der Operationen, die von dieser Berechnung verwendet werden. Wir werden daher über bestimmte gute Praktiken und gute Reflexe zur Optimierung eines Programms, unabhängig von der Sprache, sowie über bestimmte Optimierungen sprechen, die spezifischer für LeekScript sind und eng mit der Art und Weise verbunden sind, wie Operationen gezählt werden.

Falls Sie dies noch nicht getan haben, lade ich Sie ein, den Artikel LeekScript Tutorial zu lesen: Operations.

Gute Reflexe

Wenn Sie beispielsweise 500 Operationen für eine nur einmal aufgerufene Funktion speichern, werden nur 500 Operationen gespeichert. (Logik) Andererseits kann das Einsparen einer einzigen Operation bei einer Funktion, die in einer Schleife von Schleife von Schleife aufgerufen wird, die Kosten bei Operationen von mehreren zehntausend Operationen reduzieren.

Was mich zum zweiten Punkt bringt:

Die Hälfte der Arbeit beim Optimieren eines Codes besteht einfach darin, zu suchen, wo die Operationen aufhören (dann müssen Sie laut schreien und ihnen sagen, dass sie zurückkommen sollen). Was ist teuer im Code?

Dafür, kein Geheimnis, wir messen!

In unserem Arsenal bietet das LeekScript eine Funktion, die sich als sehr nützlich erweisen wird: getOperations. Diese Funktion ermöglicht es, die Anzahl der bisher im Code durchgeführten Operationen zu erfahren.

Beispiel für ein einfaches Tool zur Messung der Kosten einer Funktion:

globale __debug_operation; Funktion startOp(){ __debug_operation = getOperations(); } Funktion stopOp(Titel){ let ops = getOperations()-__debug_operation - 3; debug("Operationen (" + title + "): " + ops); }

startOp(); stopOp("leerer Test"); // leerer Test: 0

startOp(); say("Hallo Welt"); stopOp("Hallo Welt"); // Hallo Welt: 30

Wir können also bestätigen, dass das sagen wir 30 Operationen kostet, wie in der Dokumentation angekündigt.

Es ist möglich, und ich empfehle dringend, dass Sie Tools entwickeln, um andere Dinge in Ihrer KI zu messen, wie z. B. die Anzahl der Aufrufe einer Funktion sowie ihre durchschnittlichen Kosten, wodurch die Entwicklung der Kosten in Ihrer KI besser gemessen werden kann. und die Auswirkungen bestimmter Optimierungen.

Auf der Seite Komplexität erfahren Sie, warum ein Algorithmus teuer ist und wie Sie das Problem lösen können. Um es ganz einfach zusammenzufassen, wir ziehen es vor, Verschachtelungsschleifen zwischen ihnen so weit wie möglich zu vermeiden. Wir werden auch versuchen, die Größe unserer Schleifen zu begrenzen, indem wir beispielsweise nur unsere zugänglichen Zellen durchsuchen, anstatt alle Zellen der Karte zu durchsuchen. Es ist wichtig zu beachten, dass ein Algorithmus mit geringerer Komplexität * viel weniger Operationen für eine ausreichend große Anzahl von zu verarbeitenden Elementen verwendet. Denken Sie darüber nach, bevor Sie versuchen, kleine Optimierungen zu streichen!

Schleifen entfernen, die sich nicht ändern

Stellen Sie sich folgenden Code vor:

lass TP = getTP();

// schieße so oft wie möglich auf den Feind! for (var i = 0; i < floor(TP / getWeaponCost(getWeapon())); i++) { useWeapon(getNearestEnemy()); }

Die Funktion getNearestEnemy wird bei jeder Iteration der Schleife aufgerufen, während sie immer das gleiche Ergebnis zurückgibt! Um dies zu vermeiden, fügen Sie das Ergebnis einfach in eine Variable vor der Funktion ein. Das Gleiche machen wir für floor(TP / getWeaponCost(getWeapon())), das ebenfalls bei jeder Iteration ausgewertet wird. Welche geben:

lass TP = getTP();

// schieße so oft wie möglich auf den Feind! var feind = getNearestEnemy(); var nbShots = floor(TP / getWeaponCost(getWeapon())); // Anzahl möglicher Schüsse mit der aktuellen Waffe für (var i = 0; i < nbShots; i++) { useWaffe (Feind); }

Leek Wars-Features, die teuer sind

inArray, das inArray ist praktisch, es tut, was wir wollen, aber es verursacht erhebliche Betriebskosten, die wir nicht unbedingt auf den ersten Blick bemerken. Tatsächlich sieht es im Inneren so aus:

Funktion inArray(Element, Array){ for (var-Wert im Array) if (Wert == Artikel) gib true zurück; falsch zurückgeben; }

Dieses Beispiel ist eine gute Illustration, um über ein bisschen Komplexität zu sprechen. Wir sehen hier, dass die tatsächlichen Kosten dieser Funktion im schlimmsten Fall von der Größe des Arrays array abhängen, das wir n* nennen werden. Diese Funktion hat also eine Komplexität *n, das ist sie