Speedoptimierung | |
![]() | Während meiner Bundeswehrzeit konnte ich nur einen vernünftigen Spruch hören: "Geschwindigkeit ist keine Hexerei". Ich muss sagen, dieser Spruch ist tatsächlich korrekt. Natürlich kann man schnelle Programme schreiben, wenn die Programmiersprache selbst schnell ist. Nur es gibt einige Sachen, die die Programme nochmals beschleunigen können... |
#1 - Sinnloses meiden | |
Jeder Mensch macht immer nur das was am einfachsten geht. Niemandem würde in den Sinn kommen etwas sinnlosen ständig und immer wieder zu machen. Merkwürdigerweise wird das bei der Programmierung schnell vergessen. So werden ständig irgendwelche Befehle ausgeführt die überhaupt nicht notwendig sind. Darum empfehle ich euch: Setzt viele IF-THEN-Bedingungen und führt nur die Befehle aus die tatsächlich benötigt werden. | |
#2 - Integer benutzen | |
BlitzBasic hat drei Variablentypen: Integer, Float und String. Integer ist die schnellste Variante. Float ist wesentlich langsamer. Strings sind am langsamsten. | |
#3 - Float meiden | |
Kommt bei Berechnungen ein Wert mit Kommazahl vor, dann wird intern nicht mit Integern gerechnet, sondern mit Floatwerten. Dadurch wird die Berechnung stark verlangsamt. | |
#4 - Wenig Daten | |
Reserviere und Benutze möglichst wenig Daten (in Feldern, Types, Banks...). Lade möglichst wenig Multimediadateien (Bilder, Sounds). Wird der Speicher knapp, dann werden einige Daten von Ram auf wesentlich langsamere Festplatte verschoben. Dadurch kann das Programm so langsam werden, dass es unbrauchbar wird. | |
#5 - Werte merken | |
Einige Funktionsaufrufe können eingespart werden. So kann man ImageWidth und ImageHeight vor einer Schleife ausführen und die Werte zwischenspeichern: FOR y=0 to IMAGEHEIGHT(bild)-1 FOR z=0 to IMAGEWIDTH(bild)-1 ... NEXT NEXT das ist schneller: grx=IMAGEWIDTH(bild)-1 gry=IMAGEHEIGHT(bild)-1 FOR y=0 to gry FOR z=0 to grx ... NEXT NEXT | |
#6 - Teilergebnisse | |
Manche Formeln sind sehr ähnlich. So kann man einen Teil der Formel rausnehmen und separat berechnen. Danach dieses Ergebnis in den anderen Formeln verwenden. | |
#7 - Vorberechnen | |
Einige Daten werden ständig gebraucht und berechnet, obwohl das total unnötig ist. Erstelle ein Feld und speichere alle vorberechnete Werte. Dies kann z.B. mit Sqr, Cos und Sin erfolgen: DIM feld#(359) FOR i=0 TO 359 feld#(i)=SIN(i) NEXT | |
#8 - Vorberechnen 2 | |
Meistens wird ein Sin- oder Coswert mit einer Zahl multipliziert. Dies kann man in einigen Fällen auch vorberechnen. Zudem kann man in solchen Fällen oft auf die Floatvariable verzichten: radius=100 DIM feld(359) FOR i=0 TO 359 feld(i)=SIN(i)*radius NEXT | |
#9 - Berechnungen auslassen | |
Bei sehr kritischen Berechnungen kann man einige Funktionen auslassen. So z.B. bei Ermittlung von einem Radius: IF SQR((x1-x2)^2+(y1-y2)^2)=10 THEN... das ist schneller: IF (x1-x2)^2+(y1-y2)^2=100 THEN... | |
#10 - Const | |
Benutze möglichst Konstanten. Konstanten sind schneller als globale oder lokale Variablen. Da eine Konstante nie geändert wird, weiß BlitzBasic den Wert immer sofort. | |
#11 - Umschaltung 0/1 | |
Soll ein Wert ständig zwischen 0 und 1 geändert werden, dann ist das die schnellste Möglichkeit: aus=1-aus ersetzt das: IF aus=0 THEN aus=1 ELSE aus=0 | |
#12 - Bit-Operationen | |
Benutze die Funktionen AND um zu ermitteln, ob ein Bit gesetzt ist. Benutze OR um ein Bit einzuschalten. Benutze XOR um ein Bit zwischen zwei Zuständen umzuschalten. Durch diese Möglichkeiten kann man mehrere Daten in eine Variable packen - dadurch kann die Speicherbelastung enorm gesenkt werden: auslesen=SGN(wert AND 1) einschalten=wert OR 1 umschalten=wert XOR 1 | |
#13 - Multitasking | |
Starte möglichst wenig Programme gleichzeitig. Besonders Programme die im Hintergrund arbeiten können BB verlangsamen. | |
#14 - Debug | |
Deaktiviere den Debug-Modus im BB-Editor. Das bringt eine enorme Geschwindigkeitssteigerung. | |
#15 - Sgn meiden | |
Sgn ist eine sehr simple Operation. Ersetze es durch eigene (nur bei Integer!): x=SGN(wert) das ist schneller: x=(wert>0)-(wert<0) | |
#16 - Sgn meiden 2 | |
Sgn liefert Werte -1, 0 und 1. Wie wäre es mit einer spezialisierten Funktion, die dadurch noch schneller ist: x=SGN(wert) das liefert nur 0 oder 1: x=(wert>0) das liefert nur 0 oder -1: x=-(wert<0) | |
#17 - Zählungen | |
Bei ständigen konstanten Zählungen zwischen zwei Werten, kann man If-Then-Bedingungen durch schnellere Mod ersetzten (nur bei Integer!): win=win+1 IF win=360 THEN win=0 das ist schneller: win=(win+1) MOD 360 | |
#18 - Schleifen meiden | |
Die Schleifen sind etwas langsam, deshalb sollte man auf die möglichst ganz verzichten (wie man sieht ist kürzerer Code nicht immer schneller!): FOR i=1 TO 3 IF spieler(i)=1 THEN ... NEXT diese Zeilen sind schneller: IF spieler(1)=1 THEN ... IF spieler(2)=1 THEN ... IF spieler(3)=1 THEN ... | |
#19 - Schleifensprung | |
Manchmal sind Schleifen unumgänglich. Darum kann man manchmal mit einem Schleifensprung mehr erreichen: FOR i=1 TO 100 blub(i)=1 NEXT diese Zeilen sind schneller: FOR i=1 TO 100 STEP 2 blub(i)=1 blub(i+1)=1 NEXT | |
#20 - DIM | |
Nach Möglichkeit sollen statt Type-Felder normale Dim-Felder benutzt werden. Die einfachen Felder sind 100% schneller - zudem kann ein Zugriff sofort erfolgen - dies bringt nochmals mehr Speed. | |
#21 - Bedingungen | |
Die If-Then-Bedingungen können manchmal zusammengefasst werden. Dies beschleunigt das Programm leicht: IF x=1 THEN IF y=1 THEN ... ENDIF ENDIF das ist schneller: IF x=1 AND y=1 THEN ... | |
#22 - Bedingungen vereinfachen | |
Manchmal lassen sich die If-Then-Bedingungen vereinfachen. Dies kann so erfolgen: IF x=1 and y=1 THEN... das ist schneller: IF x+y=2 THEN... | |
#23 - Bedingungen weglassen | |
Manchmal lassen sich die If-Then-Bedingungen entfernen. Dies kann so erfolgen: IF x=>100 THEN dummy=1 das ist schneller: dummy=(x=>100) | |
#24 - Select statt If | |
Bei vielen sehr einfachen Bedingungen genügt Select-Case-Konstruktion. Dies bringt auch mehr Geschwindigkeit. IF x=1 THEN ELSEIF x=2 THEN... ELSEIF x=3 THEN... ENDIF das ist schneller: SELECT x CASE 1 CASE 2 CASE 3 END SELECT | |
#25 - Gosub statt Function | |
Der Befehl Gosub ist wesentlich schneller als Function. Der Unterschied ist sogar sehr gewaltig. Darum nehmt besser Gosub. Dies kann aber oft zu unübersichtlichen Programmen führen. | |
#26 - Programmsprung | |
Vermeide Programmsprünge mit Goto, Gosub und Function. Je weniger, desto besser lautet hier die Devise. Dadurch kann aber die Größe des Quellcodes steigen. | |
#27 - Daten laden | |
Vielfach ist es notwendig irgendwelche Daten zu laden. Manchmal kann man es sehr einfach und schnell mit den Banks erledigen. Benutzt dazu einfach CreateBank und ReadBytes. Speichern geht auch, mit WriteBytes. | |
#28 - Grafik meiden | |
Die Grafik ist der Speedkiller Nummer 1. Während simple Berechnungen einem PC nur ein müdes lächeln zaubern, kann eine komplexe Grafik einen PC in die Knie zwingen. Zeichnet darum nur das ein, was auch geändert werden muss. Es muss nicht der komplette Bildschirmbereich sein - schon einige Teilbereiche zu aktualisieren kann Wunder wirken. | |
#29 - Farbtiefe | |
Die benutzte Farbtiefe hat enorme Einflüsse auf die Programmgeschwindigkeit. Bei 16 Bit Farbtiefe erreichen Programm die maximale Geschwindigkeit. 24 Bit sind langsamer. Bei 32 Bit ist die Grafik am langsamsten. | |
#30 - Auflösung | |
Je größer die Auflösung, desto langsamer erfolgt die Grafikausgabe. Das kommt daher, weil die Grafikkarte wesentlich mehr Daten schaufeln muss. Meine Empfehlung liegt bei 640x480. Zur Not geht 800x600 auch noch. | |
#31 - Vollbild | |
Starte dein Programm im Vollbild. Wenn ein Programm im Fenster läuft, dann übernimmt Windows eigenständig die Aktualisierung des Fensters. Laut FPS-Counter sieht es sogar schneller aus - in Wirklichkeit wird das Bild aber wesentlich seltener aktualisiert. | |
#32 - Pixelbild aus Dim | |
Nehmen wir mal an, du benutzt ReadPixelFast um die Farbe aus einem Image zu lesen und WritePixelFast um es dann einzuzeichnen. Dies kann mit spezieller Technik beschleunigt werden. Lese das Bild aus einem Image in ein Dim-Feld Pixel für Pixel mit ReadPixelFast ein. Nun kannst du die Daten ganz einfach ohne irgendwelche Befehle direkt auslesen und mit WritePixelFast einzeichnen. Beachte, dass das Bild danach aus dem Video-Ram mit FreeImage gelöscht werden soll. Ein Dim-Feld wird dagegen im langsameren Ram-Speicher gespeichert - trotzdem ist diese Methode wesentlich schneller. | |
#33 - Line beschleunigen | |
Line funktioniert nur sehr langsam. Mit einem Trick kann es beschleunigt werden. Wendet den Befehl LOCKBUFFER bei vielen Linien an. LOCKBUFFER funktioniert ausnahmsweise zusätzlich noch mit Line. Dies bring etwa 10% mehr Speed - allerdings kann Line danach nicht außerhalb des Bildschirms erscheinen. | |
#34 - Rect statt Line | |
Sollen einfache waagerechte oder senkrechte Linien gezeichnet werden? Dann benutzt besser Rect statt Line. Dies bring enorm viel Speed (über 2000%). Das liegt daran, dass Rect besonders einfache Routinen enthält und von Grafikkarte maximal beschleunigt wird. | |
#35 - Rect beschleunigen | |
Rect ist schnell. Aber es kann noch schneller gemacht werden. Dies funktioniert nur bei einer Linienbreite von einem bis zwei Pixel. Dazu setzt den Parameter Füllen auf 1 (=Standard). | |
#36 - Plot meiden | |
Plot ist sehr langsam. Es gibt deshalb einen speziellen Pixelbefehl: WritePixel. WritePixel ist wesentlich schneller. Es hat nur einen Hacken: Die Farbe muss manuell berechnet werden. Bei einer großen einfarbigen Fläche bring das den meisten Geschwindigkeitsschub. Ach ja, erscheint die Grafik nicht außerhalb des Bildschirmbereichs, dann kann auch WritePixelFast benutzt werden - es ist das schnellste überhaupt. | |
#37 - GetColor meiden | |
Mit ReadPixel kann man den GetColor-Befehl nahezu ersetzen. Das bringt etwas mehr Geschwindigkeit. Die Farbanteile müssen dann aber manuell errechnet werden. Noch schneller ist ReadPixelFast - allerdings darf es nicht außerhalb des Bildschirms angewendet werden. | |
#38 - CopyPixel | |
Sollen nur Pixelfarben kopiert werden? Dann kann CopyPixel das Programm beschleunigen. CopyPixelFast ist sogar noch schneller - allerdings darf es nicht außerhalb des Bildschirms angewendet werden. | |
#39 - Images | |
Unterlasse die Erstellung und Löschung von Images. Durch diese Grafikbefehle wird ständig Speicher reserviert/freigegeben - dies kostet Geschwindigkeit. Besser am Anfang Images erstellen und am Ende löschen. | |
#40 - Löschen meiden | |
Benutzt du ein bildschirmfüllendes Hintergrundbild? Dann kann Cls ganz entfallen. Zeichne das Bild dann aber mit DrawBlock. | |
#41 - CopyRect | |
Mit CopyRect kann man einen Bildbereich gleichzeitig kopieren und einzeichnen. Dies ist wesentlich schneller als GrabImage und DrawBlock. | |
#42 - Bilder zeichnen | |
Bilder sollen vorzugsweise mit DrawImage gezeichnet werden. Im Vergleich zu DrawBlock wird eine bestimmte Farbe erst gar nicht eingezeichnet - dies entlastet die Grafikkarte. Allerdings kann dieser Befehl selten so eingesetzt werden - meistens bei einfarbigen Hintergründen und mit Verwendung von Cls. | |
#43 - Kollision | |
Die Kollision wird meist für einige Sachen missbraucht, für die es gar nicht gedacht ist. So wird es oft für Menüs genommen. Meine Empfehlung: Versucht eine Möglichkeit zu finden es ohne die Kollision hinzukriegen. Dies kann schon mit einfacher Prüfung der Koordinate erledigt werden. Auch Prüfungen, ob man einen Rechteck, einen Kreis oder eine Ellipse angeklickt hat sind schon mit simplen Berechnungen möglich. Rechteck: IF x=>x1 AND y=>y1 AND x<=x2 AND y<=y2 THEN... Kreis: IF SQR((x-mittex)^2+(y-mittey)^2)>=radius THEN... Ellipse (radiusy=radiusx/2): IF SQR((x-mittex)^2+((y-mittey)*2)^2)>=radius THEN... Eine Kreis-/Ellipsenberechnung kann auch vereinfacht für Sechsecke benutzt werden, die "Fehlerquote" ist nur minimal... Beachtet auch, dass die Kollisionsprüfung sehr langsam sein kann. Hier die Sortierung nach Geschwindigkeit: -RectsOverlap -ImageRectOverlap -ImagesOverlap -ImageRectCollide -ImagesCollide | |
#44 - Bildergröße ändern | |
Die Größe der Bilder zu ändern ist ein sehr langsames Verfahren. Nach Möglichkeit sollte deshalb TFormFilter deaktiviert werden. Dadurch wird ein bi-linearer Filter ausgeschaltet. Es gibt Möglichkeiten ein Bild manuell zu vergrößern/verkleinern. Das schnellste Verfahren: Das Bild wird über zwei Berechnungsstufen in der Größe geändert. Zuerst wird die X-Achse gestreckt/gestaucht, danach wird die Y-Achse gestreckt/gestaucht. Die Berechnung erfolgt in FOR-NEXT-Schleifen. Das Bild wird mit CopyRect ausgeschnitten und sofort kopiert. Prinzipbeispiel: GRAPHICS 640,480,0,2 OVAL 50,50,540,380,1 verkleinern 100,50 WAITKEY() END FUNCTION verkleinern(grx,gry) FOR x=0 TO grx x2=x*(640/grx) COPYRECT x2,0,1,480,x,0 NEXT FOR y=0 TO gry y2=y*(480/gry) COPYRECT 0,y2,grx,1,0,y NEXT COLOR 0,0,0 RECT grx,0,640-grx,480,1 RECT 0,gry,grx,480-gry,1 END FUNCTION | |
#45 - Bilder drehen | |
Das Drehen eines Bildes ist sehr zeitaufwendig. Die Deaktivierung von TFormFilter kann es etwas beschleunigen. Empfehlenswert ist eine Vorberechnung am Anfang des Programms. | |
#46 - Grafiken vorberechnen | |
Nach Möglichkeit sollen Grafiken nicht während des Spiels berechnet werden. Erstelle ein Image und zeichne dorthin das Bild ein. Nun braucht man nur dieses eine Bild mit nur einem Grafikbefehl einzuzeichnen - das bringt wesentlich mehr Geschwindigkeit. Natürlich sollte das bei komplexeren Bildern verwendet werden. |