"Entscheidungsbaum" effizienter gestalten?

3 Antworten

Vorweg:

Premature optimization is the root of all evil

Also vergiss bloß nicht, zu messen, ohne eine gute Performance-Messung sind solche kleinen Optimierungen nichts wert.

Prinzipiell gibt es kaum etwas schnelleres als ein Switch.
Ich wette mit dir, der gezeigte Code ist nicht das Problem ;)

Hab's gerade mal mit C# getestet.
Mein PC schafft im Schnitt 3886233 Durchläufe pro Sekunde.
60 bis 600 mal pro Sekunde ... da kann selbst ein schwacher PC nur müde lächeln :D

Der Teil, der vom Switch ausgeführt wird bzw. der davor liegt, der wird das Problem sein. Du könntest z.B. überlegen, ob das wirklich alles 600 mal pro Sekunde ausgeführt werden muss, oder ob 200 mal auch reicht. Dann misst Du die Zeit zum letzten mal und wenn das mehr als 5ms her ist, führst Du es aus, ansonsten nicht.


chaostheorie314 
Fragesteller
 11.07.2020, 21:17

Du hast absolut recht, wie ich gerade feststellen musste. Die Switches machen überhaupt keinen Unterschied. Auch sonst nichts in meinem eigenen Code. Die Performancefresser sind die SetWorldLocation()-, AddWorldOffset()-, AddRelativeLocation() etc. -Funktionen, die ich nicht selber geschrieben habe. Vielleicht kann ich mir die mal angucken (zum Glück habe ich den Source Code) und den Code für meine Spezialfälle optimieren.

0
Palladin007  11.07.2020, 21:25
@chaostheorie314

Aber wie gesagt:
Sei sehr vorsichtig mit Performance-Optimierungen.
Die bedeuten fast immer schlechter lesbaren und wartbaren Code und meiner Erfahrung nach sind diese "Optimierungen" oft am Ende sogar schlechter, als vorher.
Daher: Immer messen!

Außerdem ist oft nicht die Optimierung des Codes die beste Optimierung, sondern dein Umdenken.
Einfachstes Beispiel sind Datenbanken, die werden schnell zu einem riesigen Zeitfresser, wenn man die Arbeitsweise aber so dreht, dass man einmal zu Beginn alles lädt, kann man viel zeit raus holen.

Eventuell hilft auch asynchronität, bei komplexen Berechnungen kann das relevant werden, es kann aber auch grandios nach hinten losgehen. Die Erfahrung hab ich erst gestern ein weiteres mal gemacht.
Die Berechnung auf einem logischen Kern: ca. 160 Sekunden.
Auf 16 logischen Kernen: Keine Ahnung, einige Minuten, hab's abgebrochen

Oder Du reduzierst die Anzahl der Aufrufe. Nur weil eine Game-Engine so schnell laufen kann, heißt das nicht, dass alles ebenfalls so schnell laufen muss. Wäre dem so, würden die Spiele noch auf dem Level von vor zig Jahren sein.
Klug entwickelte Spiele berechnen nur so viel wie nötig, was bringt es denn, wenn der Zustand eines NPCs genauso oft neu gerechnet wird, wie das Bild?

0

Gibt es jeweils nur die beiden Möglichkeiten? Falls ja:

if (TransformAnimation.LocationReferenceFrame
    == EReferenceFrame::World:) {
       if (TransformAnimation.LocationBlendMode
           == EAnimBlendMode::Absolute:) {
           //SceneComponent->SetWorldLocation
	   } else {
           //SceneComponent->AddWorldOffset
       }	
} else {	
       if (TransformAnimation.LocationBlendMode
           == EAnimBlendMode::Absolute:) {
           //SceneComponent->SetRelativeLocation
	   } else {
           //SceneComponent->AddRelativeOffset
       }	
}	

Dabei ändern sich während der Ausführung die EAnimBlendMode- und EReferenceFrame-Werte nie

Warum muss man es dann 600 mal pro Sekunde abfragen?

Oder du programmierst ein polymorphes Verhalten via Subclassing.


chaostheorie314 
Fragesteller
 11.07.2020, 20:12
Warum muss man es dann 600 mal pro Sekunde abfragen?

Die Alternative wäre, für jede mögliche Kombination der beiden Enums eine eigene Funktion zu schreiben (LocationWorldAdditive(), LocationWorldAbsolute(), LocationRelativeAdditive(), LocationRelativeAbsolute()) und einen Funktionspointer zu speichern. Ich weiß nicht, ob das schneller wäre...

0

geschachtelten CASE Anweisung absteigend nach Auftrittswahrscheinlichkeit der Bedingung sortieren.

Wenn das immer noch zu langsam ist, dann ersetze die Case switch durch eine Folge von

if ... then
elseif ...
elseif ...
elseif ...
...
else
end

mit ebenfalls absteigend sortierter Wahrscheinlichkeit des Auftretens der Ausschlussbedingung.

Und für die ganz harten:

Ein Block mit nacheinander abzuarbeitende Ausschlussbedingungen

if then exit
if then exit
if then exit
...

Sieht zwar Sch.... aus, ist aber ziemlich schnell.


Palladin007  11.07.2020, 20:48

Ich kenne die Programmiersprache nicht, aber in C# und auch anderen Sprachen wäre dein Vorschlag kontraproduktiv.

In C# kompiliert der Compiler ein Switch anders als eine If-Kette.
Er baut daraus eine JumpTable auf, anhand des HashCodes springt er zu konkreten Block, prüft nochmal mit Equals und führt dann die Aktion aus.

Bei einem If würde jeder String einzeln verglichen werden, von oben bis unten.

Das Equals ist aber langsamer, dafür muss jedes Zeichen einzeln geprüft werden.
Bei einerm JumpTable basierend auf den HashCode kann (bzw. er tut es) der Compiler den HashCode direkt berechnen und direkt in das Ergebnis schreiben.
Und Ints können extrem schnell verglichen werden.

Außerdem ist dank diesem Umstand die Reihenfolge in einem Switch egal, in einem If nicht.

0