Objektorientierung und Performance (war: "C vs. C++")



  • häää???? schrieb:

    Der Titel hat damit aber nix zu tun.

    rgrk schrieb:

    Frage:
    Welcher Vorgehensweise sollte ich den Vorrang geben?
    - Speicherbedarf
    - CPU-Last
    - Ausführungsdauer
    - etc.

    Was dir wichtig ist.

    Der Autor wollte vielmehr die Frage zum Ausdruck
    bringen ob er die Lösung mit oder ohne OOP umsetzen
    sollte und bittet die comm um Rat.



  • rgrk schrieb:

    Hi @ comm,

    zur Lösung eines Problems habe ich Anfang der 90er Jahre
    ein Programm in Turbo Pascal geschrieben und auf dessen
    Basis heute in C++ ohne OOP neu geschrieben ...

    Das gleiche Problem könnte ich auch in C++ mit OOP umsetzen ...

    Frage:
    Welcher Vorgehensweise sollte ich den Vorrang geben?
    - Speicherbedarf
    - CPU-Last
    - Ausführungsdauer
    - etc.

    Danke.

    Vielleicht (ich denke sogar: Bestimmt) solltest Du anderen Kriterien den Vorrang geben:
    - Stabilität
    - Kurze Entwicklungszeit (inkl. Test)
    - Leichte Erweiterbarkeit
    - Übersichtliche Strukturierung
    - ...

    Wenn das Programm mit seinem Laufzeitverhalten in den 90ern OK war, wird "Performance" (zusammengefasst: die von Dir o.g. Kritierien) für Dich kein besonderes Thema sein.
    (OO-C++ dürfte allein schon schneller sein als Pascal ... von den heutigen Rechnern mal ganz zu schweigen - und Speicher kostet heute nichts mehr)

    Gruß,

    Simon2.



  • Simon2, danke für Antwort.

    Frage an die comm:
    Gib es noch weitere Aspekte?

    Danke.



  • rgrk schrieb:

    Simon2, danke für Antwort.

    Frage an die comm:
    Gib es noch weitere Aspekte?

    Danke.

    Was performanter ist, entscheidet sich vermutlich vorrangig an der Qualität des Compilers. Ein OOP-Programm mit einem modernen Compiler kann schneller sein als ein 90er Jahre Pascal-Compiler. Muss aber nicht, denn OOP ist eine Programmiertechnik und die kostet Rechenzeit.

    Das ganze ist vergleichbar mit Listen: Die sind ebenso flexibler als Arrays und das bezahlt man auch mit etwas Rechenleistung.
    Der Zugriff auf virtuelle Methoden ist teurer als der Zugriff auf statische (das meint nicht static, schließt diese aber nicht aus) linkbare Methoden.

    Klassen haben nichts mit OOP zu tun, solange Du das Schlüsselwort 'virtual' vermeidest, spricht nichts gegen einen klassenorientierten Ansatz.



  • Xin schrieb:

    denn OOP ist eine Programmiertechnik und die kostet Rechenzeit.

    nein.

    man hat oft konzepte in einem oo programm die teuer sind, aber die kann man genauso in allen anderen paradigmen einbauen...

    virtual zB. da hätte man in c vielleicht eine jump table genommen.



  • Shade Of Mine schrieb:

    Xin schrieb:

    denn OOP ist eine Programmiertechnik und die kostet Rechenzeit.

    nein.

    man hat oft konzepte in einem oo programm die teuer sind, aber die kann man genauso in allen anderen paradigmen einbauen...

    Wenn man foo(bar) zu bar.foo() ändert dann bleibt das imperative Programmierung. Die Position des ersten Parameters halte ich jedenfalls nicht für interessant genug, als dass man darüber eine Abhandlung halten müsste, selbst wenn man eine Jump-Table dazupackt.

    Shade Of Mine schrieb:

    virtual zB. da hätte man in c vielleicht eine jump table genommen.

    Richtig. Und schon ist ein C-Programm objektorientiert und genauso teuer, wie ein C++-Programm mit Virtual. Wie mach die OOP-Technik einsetzt, ist nunmal von den Hilfsmitteln abhängig, die einem die Sprache anbietet.
    C-Programme sind in der Regel aber nicht OOP, weil die Jump-Tables nunmal in C unhandlich sind.
    Damit spart man den Zugriff über die Jump-Table und ist damit in der Regel ohne OOP Ansatz schneller.

    Die Tatsache, dass man OOP in C über die Jumptable nutzen kann, genauso wie man Listen über ganz kleine Jumptables erzeugen kann, zeigt hoffentlich, dass bei OOP von einer Technik zu sprechen ist und nicht von einem Paradigma.

    Solange er von strukturierter Programmierung ohne OOP zu klassenorientierter Programmierung ohne OOP wechselt, bleibt alles beim alten.



  • OOP ist eine Denkweise. Das ist weit mehr als Vererbung und Methoden überschreiben.



  • Xin schrieb:

    ...solange Du das Schlüsselwort 'virtual' vermeidest, spricht nichts gegen einen klassenorientierten Ansatz.

    Ich würde diese Einschränkung nicht machen.
    Natürlich kostet ein "virtual call" etwas mehr als ein direkter .... aber die Frage ist: Kommt es wirklich darauf an ?
    Zwei Überlegungen:
    1.) Viele Anwendungen nutzen heute "virtual calls" ohne dass es sie performancetechnisch stört. WENN die Performance des Programms WIRKLICH im Test zu wünsche übrig lässt, ist die Wahrscheinlichkeit, dass die Probleme woanders herrühren oder andere Optimierungen deutlich mehr Effekt aufweisen, sehr hoch. Selbst wenn sich ein bestimmter "virtual call" als Übeltäter herausstellen sollte, ist es höchstwahrscheinlich immer noch effektiver (bzgl. des Gesamtergebnisses), diesen einen umzustricken als auf virtual komplett zu verzichten.

    2.) In viele Fällen ersetzt ein "virtual" eine andere Differenzierungstechnik, die mindestens ebenso performancerelevant wäre. Wenn der call statisch ist, aber danach über if- oder case-Orgien der zu bearbeitende Fall ermittelt wird, wird das Ergebnis nicht besser.

    IMO sind "virtual functions" eine gute Einrichtung und ihr "Performancenachteil" wird zu Unrecht so betont.

    Gruß,

    Simon2.



  • rgrk schrieb:

    zur Lösung eines Problems habe ich Anfang der 90er Jahre
    ein Programm in Turbo Pascal geschrieben und auf dessen
    Basis heute in C++ ohne OOP neu geschrieben ...

    wieso denn das?
    es gibt ja auch moderne pascals, wie delphi oder: http://www.freepascal.org/
    natürlich OOP fähig 👍
    oder wolltest du nur C++ lernen und hast das zum spass gemacht?

    🙂



  • Simon2 schrieb:

    IMO sind "virtual functions" eine gute Einrichtung und ihr "Performancenachteil" wird zu Unrecht so betont.

    Das ist sehr einseitig geschrieben. Andersherum wird nämlich oft auch der Nutzen virtueller Funktionen übertrieben weil sie für alles mögliche eingesetzt werden, wo andere Polymorphie (solche, die zur Compilezeit aufgelöst werden kann), ausreichend wäre.

    Echte Laufzeitpolymorphie braucht man nur sehr selten und in allen anderen Fällen sollte man sie gefälligst auch nicht benutzen. Hinzu kommt noch, dass virtuelle Funktionen ein Inlining-Blocker sind. Und in einer Schleife kann sich sowas sehr schnell bemerkbar machen. Mein Lieblingsbeispiel ist der 'std::sort'-Alrithmus, der effizienter ist als jede andere mir bekannte Implementierung. Und zwar, weil die Vergleichsoperation so elegant ge-inlined werden kann, wohingegen fast alle anderen Implementierungen (inbesondere in anderen Sprachen) hier zur Laufzeit einen virtuellen Funktionsaufruf auflösen müssen (z.B. 'IComparable.CompareTo' bzw. 'IComparator.Compare' in .NET), dabei ist das total überflüssig.



  • Undertaker schrieb:

    rgrk schrieb:

    zur Lösung eines Problems habe ich Anfang der 90er Jahre
    ein Programm in Turbo Pascal geschrieben und auf dessen
    Basis heute in C++ ohne OOP neu geschrieben ...

    wieso denn das?
    es gibt ja auch moderne pascals, wie delphi oder: http://www.freepascal.org/
    natürlich OOP fähig 👍
    oder wolltest du nur C++ lernen und hast das zum spass gemacht?

    🙂

    Nein, nicht wirklich ...
    Bevor ich mich wieder in Pascal stürze
    wollte ich komplett was anderes machen ...

    Zum Glück habe ich gut dokumentiert so das
    die Semantik in den SourceCodes erhalten blieb ...

    PS.
    Dank an alle die sich kräftig beteiligt haben,
    deren Erfahrungen und Ansichten kommen anderen zugute ...



  • Simon2 schrieb:

    Xin schrieb:

    ...solange Du das Schlüsselwort 'virtual' vermeidest, spricht nichts gegen einen klassenorientierten Ansatz.

    Ich würde diese Einschränkung nicht machen.
    Natürlich kostet ein "virtual call" etwas mehr als ein direkter .... aber die Frage ist: Kommt es wirklich darauf an ?

    Prozessoren werden immer schneller und RAM immer billiger und überhaupt haben die dümmsten Bauern die dicksten Kartoffeln. Etwa so?

    Simon2 schrieb:

    Zwei Überlegungen:
    1.) Viele Anwendungen nutzen heute "virtual calls" ohne dass es sie performancetechnisch stört.

    Stimmt. Viele Anwendungen benutzen zur Dateneingabe auch den Benutzer, ohne dass es performancetechnisch stört. Wenn der Benutzer auf Ok drücken muss, dauert das eine Sekunde. Umschließt man das mit einem while, dauert's länger und macht sich performancetechnisch dann doch irgendwie bemerkbar.
    Wenn der Computer einen Takt weniger mit warten verbringt, stört das nicht. Im Inneren eines Schleifenkonstrukts, das eventuelle mehrere milliardenmale durchlaufen wird, bedeutet ein Takt hier und ein Takt da schnell eine unnötige Laufzeitänderung, die sehr wohl bemerkt wird.

    Simon2 schrieb:

    2.) In viele Fällen ersetzt ein "virtual" eine andere Differenzierungstechnik, die mindestens ebenso performancerelevant wäre. Wenn der call statisch ist, aber danach über if- oder case-Orgien der zu bearbeitende Fall ermittelt wird, wird das Ergebnis nicht besser.

    Richtig und damit wieder einen objektorientierten Ansatz, bei dem die Entscheidung, welches Objekt behandelt wird nur sehr ungünstig gewählt wurde.
    Hat er keinen objektorientierten Ansatz und einen funktionierenden Algorithmus, so wäre es dumm ihn in OOP umzusetzen. Ihn auf Klassen aufzubauen, um die Übersichtlichkeit und Wartbarkeit zu erhöhen hingegen wäre nicht verkehrt.

    Simon2 schrieb:

    IMO sind "virtual functions" eine gute Einrichtung und ihr "Performancenachteil" wird zu Unrecht so betont.

    Virtual kostet Zeit. Das heißt deswegen aber nicht, dass virtual für manche Probleme nicht die kostengünstigste Technik ist. Trotzdem kostet es Rechenzeit. Das als Unterschied zu benennen, halte ich nicht für "zu Unrecht so betont".

    Ansonsten halte ich den Punkt 'inline blocker' von Konrad Rudolph ebenfalls für extrem wichtig.
    Als ich studierte war OOP ein Modewort, es wird immernoch von vielen als eigenständiges Paradigma angesehen. Es ist eine sehr wichtige Programmiertechnik, die man bewußt und nicht generell einsetzen sollte.
    Genauso wie Arrays weiterhin die schnellste Datenstruktur bleiben, egal wie weit man Listen und Bäume optimiert.
    Wer Listen in zeitkritischen Punkten einsetzt, wo Arrays funktionieren, hat etwas falsch gemacht.



  • Xin schrieb:

    Simon2 schrieb:

    Xin schrieb:

    ...solange Du das Schlüsselwort 'virtual' vermeidest, spricht nichts gegen einen klassenorientierten Ansatz.

    Ich würde diese Einschränkung nicht machen.
    Natürlich kostet ein "virtual call" etwas mehr als ein direkter .... aber die Frage ist: Kommt es wirklich darauf an ?

    Prozessoren werden immer schneller und RAM immer billiger und überhaupt haben die dümmsten Bauern die dicksten Kartoffeln. Etwa so?

    Ich weiß nicht, was Du damit ausdrücken möchtest. Meine Intention war es, die Frage als solche mal in den Blickpunkt zu rücken, welche Rolle "Performance" in der konkreten Aufgabe wirklich hat. Man kann zum Ergebnis kommen, dass sie tatsächlich das entscheidende Kriterium ist (wichtiger als Stabilität, Entwicklungskosten, Wartbarkeit, Erweiterbarkeit, Skalierbarkeit, Systemvoraussetzungen, ...) - aber es kann auch sein, dass auch andere Kriterien eine Rolle spielen. Das kann man aber nur entscheiden, wenn man diese Frage nüchtern und ganz undogmatisch stellt.

    Es ist auch nicht die Frage, ob es "performancetechnisch merkbar" ist, sondern welches Gewicht dieser Aspekt hat. Die Welt ist halt grau.... auch in der Programmierung.

    Xin schrieb:

    ...Virtual kostet Zeit. Das heißt deswegen aber nicht, dass virtual für manche Probleme nicht die kostengünstigste Technik ist. Trotzdem kostet es Rechenzeit. Das als Unterschied zu benennen, halte ich nicht für "zu Unrecht so betont"....

    Da ich Dich nicht persönlich kenne, kann ich Dir diesen Vorwurf sowieso nicht machen und hatte das auch nicht vor.
    Aber wenn in Diskussionen über OO (oder über Performance) als erstes/einziges Argument der Performancenachteil durch virtual calls genannt wird, droht IMO eine Überbetonung. Und der wollte ich nur mit meiner Ergänzung entgegentreten und das Argument relativieren (="In Bezug zum Kontext setzen").

    Gruß,

    Simon2.



  • Xin schrieb:

    Wenn man foo(bar) zu bar.foo() ändert dann bleibt das imperative Programmierung.

    Nein. Du kannst nicht anhand eines Funktionsaufruf das Paradigma erkennen. Es mag imperativ sein aber es mag OO sein. Beide Varianten können beides sein.

    Shade Of Mine schrieb:

    virtual zB. da hätte man in c vielleicht eine jump table genommen.

    Richtig. Und schon ist ein C-Programm objektorientiert und genauso teuer, wie ein C++-Programm mit Virtual.

    Ich kann Jump Tables haben ohne OO zu denken. Früher wusste keiner was OO bedeutet und trotzdem hatten sie Lösungen für die Probleme. Alles was ich mit OO lösen kann, kann ich ohne OO lösen. Nur weil ich erst zur runtime die Funktion kenne die ich aufrufen will, ist es noch nicht OO. Beispiel: qsort().

    Solange er von strukturierter Programmierung ohne OOP zu klassenorientierter Programmierung ohne OOP wechselt, bleibt alles beim alten.

    So ein Schritt macht 0 Sinn.



  • Shade Of Mine schrieb:

    Xin schrieb:

    Wenn man foo(bar) zu bar.foo() ändert dann bleibt das imperative Programmierung.

    Nein. Du kannst nicht anhand eines Funktionsaufruf das Paradigma erkennen. Es mag imperativ sein aber es mag OO sein. Beide Varianten können beides sein.

    Ich glaube, genau darauf wollte Xin hinaus.

    Solange er von strukturierter Programmierung ohne OOP zu klassenorientierter Programmierung ohne OOP wechselt, bleibt alles beim alten.

    So ein Schritt macht 0 Sinn.

    Doch, jede Menge Sinn. Denn Klassen erlauben eben trotzdem Datenkapselung, Modularisierung und außerdem das Schaffen eines (statischen) Typsystems, das z.B. bei der Überladung benutzt werden kann. Seqan z.B. ist eine Templatebibliothek die auf Klassen aufbaut, aber eben *nicht* OO ist.


Anmelden zum Antworten