Ressourcenschonend Scripten

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Einer der schönsten Begriffe im SAMP-Universum ist neben den Worten "Dynamisch", "Selfmade" und "Zukunftsweisend" sicher auch "Ressourcenschonend".


    Klar sollte es Ziel eines guten Programmiers sein, einen effizienten und eben schonenden Code zu schreiben.
    Ich lese aber hier im Forum oft, dass es einen Ressourcengewinn gibt, wenn ich möglichst viele Variablen in einer Zeile schreibe, es also gut sei statt


    "
    new Var1;
    new Wort[180];
    new Wort2[180];


    "



    zu schreiben folgendes im Quellcode zu verwenden:



    "
    new Var1, Wort[180], Wort2[180];


    "



    Ich gebe zu, ich bewege mich hier auf Halbwissen,
    aber es ergibt für mich keinen Sinn, dass ein Quellcode der nachfolgend zu Maschinencode Compiliert wird,
    durch die andere Schreibweise in der Laufzeit wesentlich anders reagiert.



    Ich sehe aber dadurch vermehrt Einbussen in der Übersichtlichkeit und natürlich auch der Wartbarkeit des Codes.
    Auch einem weiteren oder neuen Scripter wird der Einstieg in ein solches Script schwerer gemacht.



    Kann mir hier jemand fundiert und nachvollziehbar erklären, warum also die unterschiedliche Deklarierung hier einen Unterschied während der Laufzeit ausmachen sollte?



    Vielen Dank
    Servertest

    Deine Werbung hier?
    Niemals!
    Denn hier steht GTA:Westcoast
    gtawc.de

  • Das liegt daran, das PAWN alles nach einander abarbeitet.


    Im Grunde nicht Threadsafe/sicher.
    Sprich paralelle Aufgabe sind nur zum teil realisierbar.


    Man kann dem Server / PAWN versuchen zu erzählen, dass Aufgaben paralell auzuführen sind.
    In dem man die Aufgaben aneinander reiht.


    Du kannst auch SendClientMessage(), SendClientMessage(); dem Compiler geben.


    Threaded wird das daruch aber nicht.
    Allerdings kann PAWN die Aufgabe so schneller bewältigen, da nicht nach einer nächsten Anweisung "gesucht" werden muss, sie ist ja schließlich schon bekannt.


    Als schonend würde ich das nicht bezeichnen, das ist eher Stilsache, denn wirklich etwas einsparen an Zeit oder Ressourcen tut man nicht.

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Danke für die Antwort!
    Denkst du also auch, dass wenn ich meine beiden Beispiele jeweils compilieren und dekompilieren würde, ein unterschiedliches Ergebnis hätte?
    Das klingt für mich wirklich merkwürdig.
    Klar kann ich (derzeit) kein Multithreading ausführen (0.4 komm endlich!)
    Aber ich kann mir beim besten Willen nicht vorstellen, dass wirklich durch die "Suche" nach der nächsten abzuarbeitenden Aufgabe durch Variante 2 weniger Zeit verloren geht...


    Ich hoffe man versteht was ich ausdrücken will.

    Deine Werbung hier?
    Niemals!
    Denn hier steht GTA:Westcoast
    gtawc.de

  • Denkst du also auch, dass wenn ich meine beiden Beispiele jeweils compilieren und dekompilieren würde, ein unterschiedliches Ergebnis hätte?


    Müssen wir uns jetzt wirklich nochmal mit dem Thema decompiler auseinadersetzen?


    Im Grunde wird es so sein, dass unterschiedliche Ergebnisse herauskommen würden, sofern die decompiler auch funktionieren.
    Was sie halt nicht tun.


    Klar kann ich (derzeit) kein Multithreading ausführen (0.4 komm endlich!)


    Was hat 0.4 damit zu tun?


    Auch mit 1.0 wird es ein Multithreading geben.
    Das liegt an der PAWN Instanz.


    Es wäre theoretisch möglich den Server mehrere VMs zuzuweisen, diese würden abe aneinander vorbei arbeiten, als miteinandern.
    Von daher wäre das sicherlich nicht so ganz das was wir möchten :/


    Aber ich kann mir beim besten Willen nicht vorstellen, dass wirklich durch die "Suche" nach der nächsten abzuarbeitenden Aufgabe durch Variante 2 weniger Zeit verloren geht...


    Es ist im Prinzip nicht so einfach wie ich es versucht habe zu erklären, dafür ist das zu komplex.


    Es es ist nun einmal so, dass etwas schneller vorangehen kann, wenn etwas direkt geliefert wird, als wenn man es in Bruchstücken bekommt.
    Das ist blöd zu erklären. :(

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Ich weiß nicht, warum dich das Thema Decompiler so ärgert, doch wie gesagt kann ich ab der Stelle eben genau das nicht nachvollziehen.
    Ein errechneter (compilierter) Code sollte bei den beiden Beispielen nicht anders aussehen, ergo sollte das Ergebnis nach dem Decompilen gleich nahezu identisch sein.


    Wenn mir das jemand nachvollziehbar widerlegen könnte, wäre mir mehr geholfen als mit: "Das ist blöd zu erklären"
    Trotzdem nochmal danke für deine Antwort.

    Deine Werbung hier?
    Niemals!
    Denn hier steht GTA:Westcoast
    gtawc.de

  • Ich weiß nicht, warum dich das Thema Decompiler so ärgert


    Ganz einfach, weil dadruch wieder unnötig ?Panik geschoben wird, für Sachen die nicht funktionieren.


    Ein errechneter (compilierter) Code sollte bei den beiden Beispielen nicht anders aussehen


    Wird er aber sicherlich, und zwar, weil die Anweisung im ersten Fall nach einander übergeben wird.
    Sprich Anweisung für Anweisung, dafür steht schließlich auch das ;


    Beim 2. Fall funktioniert nicht ganz so.
    Hier wird direkt übergeben, aber nacheinander abgearbeitet.
    Deswegen wird auch der generierte Code anders aussehen.


    Das müsste man auch ohne "decompilen" feststellen können.


    Die nimmst 2 Scripte die vollständig identisch sind und sich nur in der deklaration unterscheiden.
    Dann siehst du das vielleicht schon.

    "Bevor ich mir Informationen aus der "Bild" hole,
    werde ich anfangen, Wahlergebnisse danach vorauszusagen,
    neben welchen Busch unsere Katze gepinkelt hat."

    Margarete Stokowski

  • Ich habe deinen Standpunkt verstanden. Wie gesagt, beruht meine Argumentation auch teils auf Halbwissen. (42)


    Soweit ich weiß, wird aber bei Kompilierersprachen während des Compilens eine Optimierung je nach Sprache angewendet, daher ist es eben (meiner Meinung nach) nicht so einfach auf ein anderes Ergebnis zu wetten, wenn man ein Decompilen nicht durchgeführt hat. Deshalb noch einmal die bitte: Wer kann mir hier fundiert und verständlich vermitteln, dass eben wirklich ein Unterschied besteht.


    Vielen Dank

    Deine Werbung hier?
    Niemals!
    Denn hier steht GTA:Westcoast
    gtawc.de

  • das hintereinander schreiben von anweisungen ist jedoch nur ein sehr kleiner Teil von Ressourcen schonenden Scripten, wichtiger ist es Timer richtig und wenig zu verwenden, möglichst wenig Variablen zu nutzen so wir unnötige Rechenschritte zu vermeiden.
    Vor allen sollten nicht mehr verwendete PVars wieder deltet werden etc. alles was Arbeitsspeicher und cpu schont.
    Eines der Bekanntesten Beispiele kommt aus den alten Godfather Systemen, dort wurde bei OnPLayerUpdate die daten des Spielers gespeichert, dies hat bewirkt, dass die Speicherung für jeden Spieler je nach updaterate des spielers (diese ist durch handlungen höher als wenn ich dumm rum stehe). Du kannst dir bestimmt gut vorstellen, dass es dem PC nicht gut tut in der sekunde ungefähr 10 mal pro Spieler die entsprechende Spielerdatei zu öffnen und zu updaten.


    edit:
    Wie Blackace bereits sagte ist es für den Kompiler etwas anderes ob er die Befehle einzeln oder hintereinander verknüpft bekommt.
    Stell dir vor du schreibst mit Hilfe von Pawn einen Code der ähnlich einer Einkaufsliste ist:
    schreibst du den code so:
    BuyMilk(),BuyToast(),BuyCheese(),BuyCookies();


    würde das für den Compiler so viel bedeuten dass er los gehen soll und Milch, Toast, Käse und Kekse kaufen soll.


    Bei der Methode:
    BuyMilk();
    BuyToast();
    BuyChesse();
    BuyCookies();


    würdest du den Compiler sagen, dass er los gehen soll Milch kaufen, wenn er wieder zurück ist sagst du ihm er soll Toast kaufen, wenn er wieder da ist sagst du ihm er soll Käse kaufen und wenn er dannach wieder bei dir ist sagst du ihm noch er soll Keckse kaufen.


    Bei der Schnelligkeit eines Computers, wird diese Art des Ressourcenshonenden Scripten jedoch nicht viel einsparren.
    zu lesbarkeit, wenn ich mich nicht irre kannst du das ganze auch so schreiben:


    BuyMilk(),
    BuyToast(),
    BuyCheese(),
    BuyCookies();


    Ich hoffe ich habe jetzt so schlaftrunken wie ich bin keine scheisse erzählt :)

  • Resourcend schonend scriptest Du u.A. durch:

    • Möglichst wenig Variablen - Nur das nötigste
    • Mach Strings nicht größer als sie sein müssen
    • Überleg dir gut was der Server wann machen soll (Unnötig wäre z.B. alle 10 Minuten der Spieleraccount zu speichern)
    • Richtiges Nutzen von Variablen (Wenn sie nur 0 und 1 speichert nimm nen Boolean anstatt nen Integer)

    Um laggs Vorzubeugen achte außerdem darauf dass Timer sich nicht überlappen bzw. nur sehr selten. Dazu nehm ich immer Primzahlen.
    Ob jetzt 1000ms oder 997 macht keinen wirklichen Unterschied.
    Achte darauf wie Du abfragen aufbaust.
    Wenn ein Spieler z.B. berechtigt ist einen CMD auszuführen ist es unnötig die CMD-Parameter mit z.B. SSCANF zu überprüfen.
    Auch solltest Du deine Schleifen optimieren. Warum MaxPlayers benutzen wenn der Server eh nur 50 Slots hat?




    Ich hab zwar nur gefährliches Halbwissen aber wenn Du dich an diese Punkte hälst kannst Du meistens schon einiges einsparren.
    Dazu noch die Tipps von Sniper und BlackAce beachten. Die haben da wesentlich mehr Ahnung von als Ich.

  • Als Tipp, wo man Timer einsparen könnte:


    Beispielsweise beim /ad Befehl.
    Nun könnte man auf die Idee kommen, einen Timer einzusetzen, der abzählt, wann er wieder eine Werbung schalten darf. Da hätten wir aber wieder einen Timer.
    Sollte man sich also nach einer anderen Lösung umschauen: Timestamps.
    Bei allen Aktionen, die auf eine Aktion des Nutzers hin prüfen, ob er zeitlich wieder dazu in der Lage ist, würde ich Timer komplett weglassen und Timestamps verwenden.


    Beispiel:
    Im Befehl /ad =>

    if(GetPVarInt(playerid, "advertise") > time()){
    SendClientMessage(playerid, farbe, "Du darfst diesen Befehl nicht verwenden.");
    }else{
    //Werbung senden
    SetPVarInt(playerid, "advertise", time + 60000);
    }

    Timestamps sind die Sekunden seit dem 01.01.1970.
    Somit kannst du einen Zeitpunkt setzen, an dem der Spieler wieder eine Werbung schalten darf und dann beim erneuten Eingeben des Befehls überprüfen, ob der gespeicherter Timestamp des Ablaufs größer, als der aktuelle ist, denn dann wäre der Ablauf noch in der Zukunft.
    Ansonsten ist er in der Vergangenheit, was bedeutet, dass die Werbung gesendet und der Timestamp erneut gesendet werden kann.


    Dabei wird nur eine Aktion ausgeführt, welche nur beim Eingeben des Befehls ausgeführt wird.
    Bei einem Timer wird dann eine bestimmte Zeit lang in einem bestimmten Intervall eine Aktion ausgeführt, obwohl das vielleicht gar nicht vonnöten ist.


    Nur mal so, als kleiner Exkurs, weshalb man oft auf Timer verzichten und anstelle dessen Timestamps verwenden sollte.




  • Um hier noch etwas zu ergänzen.


    Der unterschied zwischen den beiden Operatoren ':' und ',' ist das bei dem Semikolon der Opcode break ausgeführt wird und bei dem Komma nicht das bedeutet das der Code schneller ausgeführt werden kann, wie BlackAce das schon angemerkt hatte, jedoch würde ich es nicht empfehlen das ganze durchgezogen im Skript zu verwenden.
    Die zwei Operatoren



    //Edit


    Das ganze kann man sich auch anschauen in dem man sein skript mit dem Kompilerparameter -a kompilierst

    Einmal editiert, zuletzt von IPrototypeI ()

  • Aber ich kann in einem Befehl z.B. statt immer ; zu nehmen auch , nehmen?

    Glaub keinem, der Dir sagt, dass Du nichts verändern kannst.
    Die, die das behaupten, haben nur vor der Veränderung Angst.
    Es sind dieselben, die erklären, es sei gut so, wie es ist.
    Und wenn Du etwas ändern willst, dann bist Du automatisch Terrorist (Die Ärzte - Deine Schuld)

  • Aber ich kann in einem Befehl z.B. statt immer ; zu nehmen auch , nehmen?


    können schon, jedoch wirst du kein Unterschied in der Performance merken. Ich mach das auch ab und zu bei multiplen returns, jedoch laut der Aussage von Y_Less kann man dadurch
    seinen ganzen Code kaputt machen sollte man das ganze durchgängig verwenden.



    return SendClientMessage(playerid,-1,"Bla"),SendClientMessage(playerid,-1,"Bla");




    Zitat

    Richtiges Nutzen von Variablen (Wenn sie nur 0 und 1 speichert nimm nen Boolean anstatt nen Integer)


    Firerfan


    Das würde ich nicht behaupten eine variabel mit dem tag bool deklariert kann braucht ebenso 4 Bytes wie ein integer.
    Da kannst du entweder auf char-arrays umschwenken oder Bit-Arrays nutzen,


    hier sind nur 32 Bitflags möglich.

    enum Bit:(<<= 1){
    A=1,
    B,
    C,
    };
    new Bit:PlayerValue[MAX_PLAYERS];


    PlayerValue[playerid] |= A;



    Zitat

    Auch solltest Du deine Schleifen optimieren. Warum MaxPlayers benutzen wenn der Server eh nur 50 Slots hat?


    Schreib an dieser stelle eher in deinem Post das man MAX_PLAYERS der slotzahl anpassen sollte.

    #undef MAX_PLAYERS
    #define MAX_PLAYERS 50


    //edit Zwei

    3 Mal editiert, zuletzt von IPrototypeI ()

  • Mysql-> Laden.
    Solltest du mit mysql etwas laden wollen, wäre es sinnlos, wenn du für jede Variable die db "öffnen" müsstest.Player[playerid][Level] = mysql_GetInt...


    Du öffnest ja auch nicht den Kühlschrank 35x um 35 Sachen rauszuholen