Performancebeeinflussung durch if-statements?

  • GM 8

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Performancebeeinflussung durch if-statements?

    Abend,

    ich würde gerne wissen, ob eine Ansammlung von if-Statements wie diese die Performance
    stark beeinflussen kann:

    GML-Quellcode

    1. //...
    2. if variable = 1 { draw_sprite(x,y,spr_1}
    3. if variable = 2 { draw_sprite(x,y,spr_2}
    4. if variable = 3 { draw_sprite(x,y,spr_3}
    5. if variable = 4 { draw_sprite(x,y,spr_4}
    6. //...


    In meinem aktuellen Projekt ist eine solche Ansammlung drin,
    allerdings will ich diese auf circa. 200 und mehr steigern und diese
    wird dann 64 mal pro Frame ausgeführt.

    Kann soetwas die Perfomance stark beeinflussen?
    Wenn ja, gibt es eine andere Möglichkeit als if-statements,
    wenn man das gleiche bezwecken will wie im obrigen Beispiel?
  • Shapow schrieb:

    allerdings will ich diese auf circa. 200 und mehr steigern und diese
    wird dann 64 mal pro Frame ausgeführt.


    Das ist eindeutig zu viel des guten.
    Wie bereits gesagt, eignet sich ein Switch-statement dafür viel besser und schont die Performance ungemein.

    200 if Abfragen für das alleinige vergleichen von Variablen in 64 FPS ist viel zu viel. Man muss bedenken dass du ja noch all die andere Spiellogik miteinbauen musst.
    Wenn dem so wäre, würde kein "normaler" Rechenr die 64 FPS erreichen, was zu einer "unterschiedlichen" Spielgeschwindichkeit führen würde. (Je Stärker der Rechner, desto flüssiger das Game.)

    /Edit:

    Hab mal ein bisschen gegooglet und
    erfahren, das in C++ bei sehr großem Umfang switch deutlich schneller ist.
    Jedoch ist der GM ein Interpreter...


    Dass der GM durch einen Interpreter ausgeführt wird, bedeutet nicht dass die ganzen Grund-befehle wie 'If und Switch (die in fast jeder Progger sprache vorkommen) auf einmal auf den Kopf gestellt werden.
    Der GM ist legendlich langsamer als C# bzw C++.

    Die Performance kann mit "switch" gegenüber tausenden von If-Anweisungen genausogut gesteigert werden wie in C++ oder Java.
  • Du kannst anstatt der Switch-Anweisung auch

    GML-Quellcode

    1. if(Ausdruck) /*Zeug*/else if(Ausdruck) /*Zeug*/else if(Ausdruck) /*Zeug*//* ...*/else /*Zeug*/



    Dann sollte der Interpreter logischerweise nicht auf die anderen Abfragen eingehen, wenn ein Ausdruck richtig ist.
    Bin mir aber nicht sicher ob das schneller interpretiert wird als switch. Aber if ohne ein else sollte man, wenn möglich, nicht benutzen (ist nicht schön).

    Albert Einstein schrieb:

    Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind.
  • Trixt0r schrieb:

    Dann sollte der Interpreter logischerweise nicht auf die anderen Abfragen eingehen, wenn ein Ausdruck richtig ist.
    Bin mir aber nicht sicher ob das schneller interpretiert wird als switch. Aber if ohne ein else sollte man, wenn möglich, nicht benutzen (ist nicht schön).


    Mann muss bei solchen heiklen Sachen immer den "worst-Case" (quasi den schlimmsten anzunehmenden Fall) betrachten.
    Dieser wäre in dem Fall die ganz letzte If-Anweisung.
    Wenn alle vorherigen if's nicht stimmen sondern erst das letzte auf true gesetzt wird, dann muss sich das Spiel logischerweise
    durch alle if-anweisungen bis zur letzten durchkämpfen.

    Die reihenfolge schaut etwa so aus: (beim if)
    "Ist die Variable True? nein? Dann mache ich dies: Ist die Variable wahr? nein? Dann mache ich dies: Ist die Variable wahr? Nein? etc..."

    Beim switch nimmt er einfach nur die Zahl, läuft schnell eine Zahlenliste ab und vergleicht sie blitzschnell miteinander.
    Dies ist viel schneller als die If-else Kombination.
    Da gibt es kei n"bis zur letzten prüfung durchkämpfen". Er nimmt sich praktisch sofort das, was er braucht.

    Man sollte wenn möglich die Performance so gut es geht auf das ganze System verteilen um diese "Leistungsspitzen" zu dämpfen.
    Switches sind ind dem Fall wirklich die beste Lösung.

    Zwischen einem Switch mit nur 1 "case" und einer If Abfrage sollte von der Performance her so gut wie kein Unterschied zu erkennen sein. Wenn man jedoch minimalistisch ist (so wie ich :D)
    kann ich mir gut vorstellen dass das Switch sogar schneller abgearbeitet wird.

    Wenn man jedoch eine If- Verschachtelung mit einem gleichsogroßem Switch gleichsetzt, so gewinnt das Switch von der Performance her um längen.
  • henrik1235 schrieb:

    wenn man das gleiche bezwecken will wie im obrigen Beispiel?
    Sprite-Indexes in eine Array speichern und dann mit Sprites[Variable] zugreifen.

    Hätte ich auch gesagt. Vor allem wenns nur um solche aufgaben geht, wo ein Sprite abhängig von einer Variable gezeichnet wird. Wenns ganz einfach geht, ist es am besten, die einzelnen Sprites in ein einziges zu verlegen und dann beim Drawen einfach mit der Variable auf den index zuzugreifen:

    GML-Quellcode

    1. draw_sprite(spr_sprite, variable /* = index */, x, y);


    Sonst so wie henrik1235 es gesagt hat: Einmal im Create Event, die zusammenhänge definieren:

    GML-Quellcode

    1. sprite[0] = spr1;
    2. sprite[1] = spr2;
    3. // usw


    und dann im Draw event über den Array index auf das Sprite zugreifen:

    GML-Quellcode

    1. draw_sprite(sprite[variable], 0, x, y);

    © 2008 by Teamgrill Productions
  • Wie bereits erwähnt, wäre ein Switch statement die einfachste und verhältnismässig ressourcenshonendste Lösung.
    Sie erfordert aber auch eine grosse Menge an Schreibarbeit deinerseits.

    Stattdessen köntest du dir (sofern dein Problem wirklich exakt wie im Beispiel angegeben) der Tatsache zunutze machen dass der GM sprites immer einem Index, sprich einer reelen Zahl zuordnet. Sobald du ein neues Sprite hinzufügst bekommt das neue Sprite die nächsthöhere Zahl.

    Somit kannst du etwa sowas schreiben:

    GML-Quellcode

    1. draw_sprite(erstes_sprite + variable ,image_index... )


    Dies setzt allerdings vorraus dass du alle Sprites nacheinander hinzufügst und zwar genau in der Reihenfolge in der sie dann der Variable entsprechend gezeichnet werden sollen.
    Sobald du irgendwo was dazwischen zu schieben versuchst oder ein Sprite löscht, bricht das System zusammen.. Du darfst aber jederzeit das Sprite, z. B. dessen Bild ohne Probleme ändern. Das gilt auch für den Namen.

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)
  • Zumindest im Delphi-Runner waren Listen noch schneller als Arrays. Vergiss für einen Moment, wie verkettete Listen eigentlich funktionieren und versuch es anstelle eines Arrays auch einmal mit einer Liste und schau, was schneller ist.
    Nicht, dass es groß eine Rolle spielen würde, aber wäre mal interessant zu wissen.
  • famous schrieb:

    DragonGamer schrieb:

    Stattdessen köntest du dir (sofern dein Problem wirklich exakt wie im Beispiel angegeben) der Tatsache zunutze machen dass der GM sprites immer einem Index, sprich einer reelen Zahl zuordnet. Sobald du ein neues Sprite hinzufügst bekommt das neue Sprite die nächsthöhere Zahl.

    Somit kannst du etwa sowas schreiben:

    GML-Quellcode

    1. draw_sprite(erstes_sprite + variable ,image_index... )


    Dies setzt allerdings vorraus dass du alle Sprites nacheinander hinzufügst und zwar genau in der Reihenfolge in der sie dann der Variable entsprechend gezeichnet werden sollen.
    Sobald du irgendwo was dazwischen zu schieben versuchst oder ein Sprite löscht, bricht das System zusammen.. Du darfst aber jederzeit das Sprite, z. B. dessen Bild ohne Probleme ändern. Das gilt auch für den Namen.
    Die ID´s in ein Array zu packen wäre da sinnvoller.


    Könntest du das vieleicht bitte auch begründen?
    Wenn man ein array benutzt, heisst es dass man für jeden Sprite ine Zeile in einem create event schreiben muss, Wenn man ordentlich arbeitet (d.h. Nicht die ganze Zeit sprites löscht) kann man sich dies mit meiner methode sparen und es auch mindestens genau so schnell (das Zugreifen auf arrays benötigt im Gm auch Zeit).


    EDIT: @MewX Meinst du was im GM schneller ist? Oder in Delphi?
    Im GameMaker sind arrays auf alle Fälle viel, viel schneller soweit ich mich erinnere. Das könnte daran liegen dass Listen über Funktionen funktionieren die der Interpreter verarbeiten muss...

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von DragonGamer ()

  • Langsam geraten wir etwas in den Off-Topic-Bereich, aber ich wollte mal meinen Senf hierzu geben.
    Laut (von mir) angestellter Tests, sind Arrays (bezogen auf 10.000 Einträge) immerhin durchschnittlich 1 Millisekunde schneller.

    Lustig, denn im Delphi-Interpreter waren lists noch die schnelleren (Dafür waren sie ursprünglich ja auch gedacht).

    Das Testergebnis:

    Quellcode

    1. Filling a list with 10000 entries took: 3.81ms
    2. Filling an array with 10000 entries took: 2.88ms


    - Tobi97
  • Shapow schrieb:

    Laut Hilfe sind Listen schneller :thumbup:
    They are implemented using simple arrays but, as this is done in compiled code
    it is a lot faster than using an array yourself.


    Dies bezieht sich auf verarbeitung der Daten in arrays bzw. Listen. Also dann wenn du die Funktionen im GM verwendest wo du für das selbe mit Arrays eine oder gar mehrere Schleifen schreiben müstest. Diese Schleifen müssten dann interpretiert werden was einiges an Zeit kostet.

    Wie auch immer, MewX kann ja selber seine Studien durchführen :D

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)

  • Filling a list with 10000 entries took: 3.81ms
    Filling an array with 10000 entries took: 2.88ms


    Laut Hilfe sind Listen schneller :thumbup:
    They are implemented using simple arrays but, as this is done in compiled code
    it is a lot faster than using an array yourself.


    Dies bezieht sich auf verarbeitung der Daten in arrays bzw. Listen. Also
    dann wenn du die Funktionen im GM verwendest wo du für das selbe mit
    Arrays eine oder gar mehrere Schleifen schreiben müstest. Diese
    Schleifen müssten dann interpretiert werden was einiges an Zeit kostet.
    Mir geht es ja nur um die Verarbeitung, nicht um das Schreiben neuer Inhalte.
  • Shapow schrieb:


    Filling a list with 10000 entries took: 3.81ms
    Filling an array with 10000 entries took: 2.88ms


    Laut Hilfe sind Listen schneller :thumbup:
    They are implemented using simple arrays but, as this is done in compiled code
    it is a lot faster than using an array yourself.


    Dies bezieht sich auf verarbeitung der Daten in arrays bzw. Listen. Also
    dann wenn du die Funktionen im GM verwendest wo du für das selbe mit
    Arrays eine oder gar mehrere Schleifen schreiben müstest. Diese
    Schleifen müssten dann interpretiert werden was einiges an Zeit kostet.
    Mir geht es ja nur um die Verarbeitung, nicht um das Schreiben neuer Inhalte.


    Nein, nein.. diese Diskusion hat nichts mit dem zutun was du brauchst. Sorry wir haben dich nur verwirrt...

    Einfach ein array benutzen (oder meine Methode). Das ist auf _jeden_ Fall performant genug da im step event keinerlei Abfragen durchgeführt wrden müssen...

    Wenn das Problem gelöst ist, kannst du ja den thread auf "gelöst" setzen, dann schreiben wir auch nicht mehr (normalerweise) xD

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)