Was ist für euch guter Programmcode?



  • Bleibt zu klären, ob es in einer realistisch umfangreichen Anwendung so zum Tragen kommt. Du kannst auch einfach schönen Code schreiben und warten, bis der JIT-Compiler den Unterschied auf 0% drückt.
    Wenn es natürlich wirklich etwas ist, was du hier und jetzt bis zum letzten optimieren und solche Kompromisse eingehen musst, gibt's nicht mehr viel zu sagen, wenn du so gemessen hast. Aber dann bist du im falschen Thread gelandet. 😉



  • Gregor@Home schrieb:

    Optimizer schrieb:

    Dass das Programm deswegen langsamer wird, glaube ich nicht, so schrottig sind die JIT-Compiler heute eigentlich nicht mehr.

    Dann muss ich dich jetzt vermutlich mal in die Realität zurückholen. 😃 Ich habe natürlich gemessen und alleine die simple Aufspaltung der Methoden, die ich da oben gemaht habe, hat das Programm an der entsprechenden Stelle 20-30% langsamer gemacht. Der JIT-Compiler beherrscht in der Theorie zwar lauter tolle Sachen, das heißt aber noch lange nicht, dass davon auch etwas in der Praxis ankommt.

    ich würde vorschlagen, du spaltest trotzdem bin ins kleinste fitzelchen. und mißt viel. das übergeben von arrays und dergleichen muß in java eigentlich sehr schnell sein. evtl bringt es was, ne eigene klasse für den n-dimensionalen vector zu machen. so mal in der hoffnung, daß java schneller auf attributen ackern kann, als auf übergebenen argumenten. und überall final rein, damit er besser inlined.
    und dann hoffe ich, daß zum schluss nur ein- oder zwei knackpunkte sind, die du entgegen dem guten stil per hand inlinest, den rest aber gefitzelt halten kannst.
    viel glück. *g*

    vielleicht bringrt es was, nen einfachen präprozessor zu bauen.



  • Optimizer schrieb:

    Bleibt zu klären, ob es in einer realistisch umfangreichen Anwendung so zum Tragen kommt. Du kannst auch einfach schönen Code schreiben und warten, bis der JIT-Compiler den Unterschied auf 0% drückt.

    so geh ich in c++ gerne vor. dauert zwar vom wunsch bis zur realisierung durch die compilerbauer 4 jahre oder mehr, aber irgendwie kommt's dann doch.



  • Optimizer schrieb:

    Bleibt zu klären, ob es in einer realistisch umfangreichen Anwendung so zum Tragen kommt. Du kannst auch einfach schönen Code schreiben und warten, bis der JIT-Compiler den Unterschied auf 0% drückt.
    Wenn es natürlich wirklich etwas ist, was du hier und jetzt bis zum letzten optimieren und solche Kompromisse eingehen musst, gibt's nicht mehr viel zu sagen, wenn du so gemessen hast. Aber dann bist du im falschen Thread gelandet. 😉

    Dann bin ich wohl im falschen Thread gelandet. 😃 Dieses Programmstück dürfte ruhig um einen Faktor 50 oder mehr schneller sein. Mein Programm würde davon enorm profitieren. Und trotzdem stellt eigentlich die erste Variante, die ich da gepostet hatte, schon einen Kompromiss dar. Ich hatte vorher schonmal die ganzen lokalen Hilfsvariablen zu Membern gemacht, was durchaus auch 20% Performance gebracht hatte, bin davon aber wieder abgekommen, weil es letztendlich einer Parallelisierung im Weg steht, die ich durchführen möchte, wenn ich mir irgendwann mal ein Mehrkernsystem zulegen sollte. Ich habe da also eigentlich schon die "Premature Optimizations" entfernt, die mich in der Wartung des Codes wirklich behindern.

    PS: Du siehst es also auch so, dass man manchmal Kompromisse bezüglich der Qualität eingehen muss? Man hört ja oft, dass ein gutes Design und ein guter Stil auch zu schnellem Code führt. Offensichtlich ist das nur eingeschränkt gültig und manchmal sind die Ziele "guter Stil" und "Performance" nicht so leicht in Einklang zu bringen.



  • volkard schrieb:

    und überall final rein, damit er besser inlined.

    Leider ist es nur ein Gerücht, dass final bezüglich der Performance hilft. Wenn man von Konstanten primitiver Typen absieht, dann hat final keinerlei Auswirkungen auf die Performance. Normalerweise ist "final" etwas, das nur mit dem Design zu tun hat und teilweise überlebt es nichtmal bis in den Bytecode (Zum Beispiel bei Methodenparametern).

    Wenn ich irgendwo eine Methode als "private final" deklariere, dann ist das "final" da eigentlich auch überflüssig. Das steckt praktisch schon im "private" drin. Der Jitter ist beim Inlining auch nicht auf das "final" angewiesen. ...naja, aber wie du schon sagst: Ich warte mal 4 Jahre, vielleicht nutzt das der Jitter oder der Bytecode-Compiler ja irgendwann mal.



  • Gregor@Home schrieb:

    Dieses Programmstück dürfte ruhig um einen Faktor 50 oder mehr schneller sein.

    Öhm, naja: "Mit einem anderen Programmstück zusammen.". Und zwar das, was sich im "pointProcessor" verbirgt.



  • Worauf wartest du genau? Mir fällt kein Szenario ein, indem final ein Hinweis für den JIT-Compiler sein könnte, eine Methode nicht virtuell aufzurufen. Er kennt alle geladenen Klassen (weiß also welche Methode bis zu welcher Ableitung redefiniert wird), den Referenztyp und weiß daher IMHO genau, ob es klar ist, welche Methode das ist, oder nicht. Könnte ein final irgendwo noch ein Mehr an Informationen bringen?

    PS: Du siehst es also auch so, dass man manchmal Kompromisse bezüglich der Qualität eingehen muss? Man hört ja oft, dass ein gutes Design und ein guter Stil auch zu schnellem Code führt. Offensichtlich ist das nur eingeschränkt gültig und manchmal sind die Ziele "guter Stil" und "Performance" nicht so leicht in Einklang zu bringen.

    Ich denke, gutes Design macht das Programm nicht von sich aus schneller, aber kann das Optimieren auf höherer Ebene vereinfachen. Ich weiß nicht, ob ich auch Kompromisse beim Design eingehen würde, bisher ist die Optimierung mit meiner bescheidenen Mathematik immer schon auf der Algorithmen-Ebene zu früh zum Stillstand gekommen. Da bringt's dann wohl auch nichts mehr, auch noch zusätzlich das Design zu zerstören, wenn noch so viel Potenzial brach liegt.



  • Gregor@Home schrieb:

    Du siehst es also auch so, dass man manchmal Kompromisse bezüglich der Qualität eingehen muss? Man hört ja oft, dass ein gutes Design und ein guter Stil auch zu schnellem Code führt. Offensichtlich ist das nur eingeschränkt gültig und manchmal sind die Ziele "guter Stil" und "Performance" nicht so leicht in Einklang zu bringen.

    ich erinnere mich an meine basic-zeit.
    auf dem zx81 (nur double-variablen und strings) schrieb man in schleifen pi statt 3 als obergrenze, weil es nur ein token war (und ein byte verbrauchte) und kein double-literal. man schreib auch "sqrt pi" statt 1, sind ja nur 2 bytes so. mit 1k ram ist code-size einfach was wichtiges.
    auf dem 64-er benutze man next für rücksprunge.
    also (mal ohne abbruchbedingung)

    7810 for i=0 to 1 step 0
    7820 print "volkard ist doof"
    7830 next
    

    statt

    7810 print "volkard ist doof"
    7820 goto 7810

    denn gote hat von anfang bis zum fund die verkettete liste der zeilen durchsucht, bis die zeilennummer gefunden wurde. also o(vorherigeZeilenAnzahl). next hingegen hat die adresse des for-befehls gespeichert, also o(1).
    dann viel qbasic. da ist nix passiert. es wurde nur immer bessew als basic v.2.
    in visual-basic lebt ein großes verbrechen bis heute. man will die anzahl der zeilen einer datei wissen. mit ner schleife ienlesen und zählen ist lahm. man liest besser die gesamte datei in einen string, macht ein replace(inhalt,chr(13),""), also ersetzt alle \n durch nix, und berechnet die differenz der größen der strings vorher und nachher.
    dann irgendwann c. aber noch c als makro-assembler. der compiler hat so toll optimiert, wie der hund meines nachbarn. also immer strcpy statt schleife, immer dies und das, was der compilerbauer liefert, statt ner simplen schleife. wüsten herumgecaste, daß es klappt.
    dann kam c++. keine änderung. bei c++ bin ich geblieben, aber die compiler sind viel besser geworden.
    bin jetzt seit +5 jahren bei nem stil, wo ich code von vor 5 jahren flüssig lesen kann. den frühen c-code von mir konnte ich nach 6 monaten nicht im geringsten lesen. hab gar nix gerafft. obwohl ich den algo genau kannte und der source nur über 3 bildschirme ging. nix.

    es ist irgendwie schlimm, wenn die performance bestimmt, *wie* du etwas hinschreiben musst. toll wäre, wenn du einfach das schreiben dürftes, was dur für am besten lesbar hälst, und der compiler macht zuverlässig optimalen code draus.

    ich ertappe mich auch immer wieder bei meinen ausflügen php (perl hat zwar das gleiche problem, aber da mogle ich nie), wie ich schönen code zu häßlichem mache, weil der häßliche signifikant schneller ist.



  • Optimizer schrieb:

    Worauf wartest du genau? Mir fällt kein Szenario ein, indem final ein Hinweis für den JIT-Compiler sein könnte, eine Methode nicht virtuell aufzurufen. Er kennt alle geladenen Klassen (weiß also welche Methode bis zu welcher Ableitung redefiniert wird), den Referenztyp und weiß daher IMHO genau, ob es klar ist, welche Methode das ist, oder nicht. Könnte ein final irgendwo noch ein Mehr an Informationen bringen?

    Vielleicht könnte es javac noch mehr Informationen bringen. Momentan optimiert der ja AFAIK gar nicht, aber vielleicht entschließen die sich irgendwann wieder dazu, javac statische Optimierungen machen zu lassen. Da könnte ein final dann durchaus eine hilfreiche Information sein. ...IMHO, habe mir da allerdings keine tiefergehenden Gedanken gemacht.



  • Gregor@Home schrieb:

    naja, aber wie du schon sagst: Ich warte mal 4 Jahre, vielleicht nutzt das der Jitter oder der Bytecode-Compiler ja irgendwann mal.

    jo, wart mal.
    ich glaube fest daran, daß es theoretische gründe gibt, weshalb java schnelleren code generieren kann als c++.
    so, wie ich ich immer dran glaubte, daß in c++ cout theoretsch schneller als printf ist. ka, wie weit der nachweis gediegen ist. aber zur not, werde ich das selber schaffen.
    irgendwann wird java-compilat schneller als c++-coimpilar rennen und dann wird der gcc bald ne option -fno_reinterpretcast anbieten und noch allerlei. es wird c++-nach-java-compiler geben. und ich werde feststellen, daß ich mehrfache erblichkeit in 1000 klassen nur einmal brauche und mit zei ifs an performance-unkritischen stellen krieg ich die auch weg.



  • volkard schrieb:

    und ich werde feststellen, daß ich mehrfache erblichkeit in 1000 klassen nur einmal brauche und mit zei ifs an performance-unkritischen stellen krieg ich die auch weg.

    Hmmm. Ich weiß gerade nicht, was Mehrfachvererbung mit zig ifs zu tun hat. Aber ich nutze in Java IMHO eigentlich relativ wenig ifs und auch wenig switch, weil bei mir eigentlich nahezu alles durch so eine Art Funktionsobjekt repräsentiert wird. Ich nutze also Polymorphie und "konfiguriere" Algorithmen usw. eher, als dass ich in Algorithmen mit lauter ifs auf irgendwelche Dinge anders reagiere. Stattdessen tausche ich einfach diese "Funktionsobjekte" aus.

    Ist das eigentlich eine übliche Technik, um die ganzen ifs zu beseitigen? Ich habe bei mir festgestellt, dass die ifs immer zu Code führen, der sich bei wachsendem Programm lokal vergrößert. Aus 3 ifs werden dann plötzlich 5, 7, 10 oder was weiß ich wie viele. Ich habe das eigentlich noch nie so konsequent in anderem Code gesehen, wie ich es durchziehe. Andererseits gucke ich mir kaum anderen Code an und eine if-Orgie fällt eher auf als keine.



  • http schrieb:

    lol. die http request parse funktion ist dort ja noch länger. 739 zeilen. das kann doch echt nicht wahr sein. 🙄

    http://www.rafb.net/paste/results/Kr6OVH70.html

    Alles eine Sache der Erfahrung. Für Power Off z.B. ist dieser Code ziemlich trivial.



  • trivial- schrieb:

    Alles eine Sache der Erfahrung. Für Power Off z.B. ist dieser Code ziemlich trivial.

    Stimmt. Nix besonderes. Besteht eh hauptsaechlich aus Log-Aufrufen.



  • Gregor@Home schrieb:

    volkard schrieb:

    und ich werde feststellen, daß ich mehrfache erblichkeit in 1000 klassen nur einmal brauche und mit zei ifs an performance-unkritischen stellen krieg ich die auch weg.

    Hmmm. Ich weiß gerade nicht, was Mehrfachvererbung mit zig ifs zu tun hat.

    ich füchte, ich meinte mit "zei" eher "zwei" als "zig".



  • den find ich nice 😋

    http://www.rafb.net/paste/results/QUKLrK92.html

    1889 Zeilen, eine Funktion.



  • holy wtf schrieb:

    den find ich nice 😋

    http://www.rafb.net/paste/results/QUKLrK92.html

    1889 Zeilen, eine Funktion.

    LOL, hauptsache erstmal 100 Zeilen ASCII-Diagramme im Code einbauen...



  • LOL



  • besserwisser schrieb:

    int main()
    {
        loese_die_problemstellung();
    
        return 0;
    }
    

    Das perfekte Programm imo. Sorry für's Ausgraben dieses alten Urthreads, aber wenn ein Programm einmal bei mir jemals so aussehen sollte, hab ich modulare, objektorientierte, prozedurale und generische Programmierung endgültig verstanden. Hammer! Wie schreibt man solche Funktionen?


Anmelden zum Antworten