Optimalisatie

Optimalisatie

> LeekScript-zelfstudie

Hier zullen we het hebben over optimalisatie, het doel van optimalisatie is om de prestaties van een algoritme te verbeteren. Als we het over optimalisatie hebben, hebben we het in het algemeen over uitvoeringstijd, met als doel de tijd die nodig is om een reeks instructies uit te voeren, te verkorten.

In LeekScript wordt deze uitvoeringstijd geschat door een getal: het aantal bewerkingen dat door deze berekening wordt gebruikt. We gaan het daarom hebben over bepaalde goede praktijken en goede reflexen voor het optimaliseren van een programma, ongeacht de taal, evenals bepaalde optimalisaties die meer specifiek zijn voor LeekScript en nauw verband houden met de manier waarop bewerkingen worden geteld.

Als je dat nog niet hebt gedaan, nodig ik je uit om het LeekScript Tutorial artikel: Operations te lezen.

Goede reflexen

Als u bijvoorbeeld 500 bewerkingen opslaat voor een functie die slechts één keer wordt aangeroepen, worden er slechts 500 bewerkingen opgeslagen. (logica) Aan de andere kant kan een besparing van een enkele bewerking op een functie die wordt aangeroepen in een lus of lus of lus de kosten van bewerkingen van enkele tienduizenden bewerkingen verlagen.

Dat brengt me bij het tweede punt:

De helft van het werk van het optimaliseren van een code bestaat simpelweg uit het zoeken naar waar de bewerkingen vertrekken (dan moet je luid roepen en zeggen dat ze terug moeten komen). Wat is duur in de code?

Daarvoor, geen geheim, we zullen meten!

In ons arsenaal biedt het LeekScript een functie die zeer nuttig zal blijken te zijn: getOperations. Deze functie maakt het mogelijk om het aantal bewerkingen te weten dat tot nu toe in de code is uitgevoerd.

Voorbeeld van een eenvoudig hulpmiddel om de kosten van een functie te meten:

globale __debug_operatie; functie startOp(){ __debug_operation = getOperations(); } functie stopOp(titel){ let ops = getOperations()-__debug_operation - 3; debug("Bewerkingen (" + titel + "): " + ops); }

startOp(); stopOp("lege test"); // lege test: 0

startOp(); say("hallo wereld"); stopOp("hallo wereld"); // hallo wereld: 30

We kunnen dus bevestigen dat het 30 operaties kost, zoals aangekondigd in de documentatie.

Het is mogelijk, en ik raad u ten zeerste aan om tools te maken om andere dingen in uw AI te meten, zoals het aantal oproepen naar een functie, evenals de gemiddelde kosten, waarmee u de evolutie van de kosten in uw AI beter kunt meten. en de impact van bepaalde optimalisaties.

De pagina Complexiteit helpt u te begrijpen waarom een algoritme duur is en hoe u het probleem kunt oplossen. Om het heel eenvoudig samen te vatten, we geven er de voorkeur aan zoveel mogelijk geneste lussen ertussen te vermijden. We zullen ook proberen de grootte van onze lussen te beperken, bijvoorbeeld door alleen door onze toegankelijke cellen te bladeren in plaats van door alle cellen van de kaart te bladeren. Het is belangrijk op te merken dat een algoritme met een lagere complexiteit veel minder bewerkingen zal gebruiken voor een voldoende groot aantal items om te verwerken, denk daar eens over na voordat u kleine optimalisaties probeert te schrappen!

Loops verwijderen die niet veranderen

Stel je de volgende code voor:

laat TP = getTP();

// schiet zo vaak mogelijk op de vijand! voor (var i = 0; i < vloer(TP / getWeaponCost(getWeapon())); i++) { gebruikWeapon(getNearestEnemy()); }

De functie getNearestEnemy wordt aangeroepen bij elke iteratie van de lus, terwijl het altijd hetzelfde resultaat oplevert! Om dit te voorkomen, plaatst u het resultaat gewoon in een variabele vóór de functie. We doen hetzelfde voor floor(TP / getWeaponCost(getWeapon())) dat ook bij elke iteratie wordt geëvalueerd. Welke geven:

laat TP = getTP();

// schiet zo vaak mogelijk op de vijand! var vijand = haal Dichtstbijzijnde Vijand(); var nbShots = verdieping(TP / getWeaponCost(getWeapon())); // aantal mogelijke schoten met het huidige wapen voor (var i = 0; i < nbShots; i++) { gebruik Wapen (vijand); }

Leek Wars-functies die duur zijn

inArray, de inArray is praktisch, het doet wat we willen, maar het brengt aanzienlijke kosten met zich mee in operaties die we op het eerste gezicht niet per se opmerken. In feite ziet het er van binnen zo uit:

functie inArray(element, array){ voor (var-waarde in array) als (waarde == element) retourneer waar; retourneer vals; }

Dit voorbeeld is een goede illustratie om over een beetje complexiteit te praten. We zien hier dat de werkelijke kosten van deze functie in het slechtste geval afhangen van de grootte van de array array, die we n* zullen noemen. Deze functie heeft dus een complexiteit *n, dat is het