Performance bei Objektauf-/-abbau



  • Hallo,

    wie ist denn eigentlich die Größenordnung der benötigten Zeit /Performance beim Klassen konstruieren/zerstören.
    zB:

    1.
    //Global
    CKlasse myclass;
    
    void foo()
    {
       myclass.bar();
    }
    
    2.
    void foo()
    {
       CKlasse myclass;
       myclass.bar();
    }
    

    Nehmen wir an, dass die Funktion foo sehr oft aufgerufen wird. Um welchen Faktor ist denn 2 langsamer als 1. Kann man das in einem Größenverhältnis angeben?

    Und wie sieht das bei COM aus? Wenn nun CKlasse ein COM Objekt wäre? Wie ist da das Performanceverhältnis?

    Gruß

    PS: alles in C++, Die Klasse CKlasse ist eine ganz Kleine und implementiert nur die Methode bar sonst nichts. (hoffe das reicht als Angabe)



  • electron schrieb:

    wie ist denn eigentlich die Größenordnung der benötigten Zeit /Performance beim Klassen konstruieren/zerstören.
    zB:

    1.
    //Global
    CKlasse myclass;
    
    void foo()
    {
       myclass.bar();
    }
    
    2.
    void foo()
    {
       CKlasse myclass;
       myclass.bar();
    }
    

    Nehmen wir an, dass die Funktion foo sehr oft aufgerufen wird. Um welchen Faktor ist denn 2 langsamer als 1. Kann man das in einem Größenverhältnis angeben?

    Diese beiden Funktionen erfüllen völlig verschiedene Aufgaben, deswegen sind das keine Alternativen. Genausogut könntest du eine quicksort-Funktion mit einer printf-Funktion vergleichen.

    Der Zeitaufwand ein Objekt zu konstruieren kann von vernachlässigbar bis immens reichen. Das hängt davon ab, wie aufwändig der Konstruktor ist. In einem konkreten Fall kannst du das nur sicher feststellen, indem du die Zeit misst. In deinem Fall dürfte der Aufwand wahrscheinlich vernachlässigbar sein.



  • Christoph schrieb:

    Diese beiden Funktionen erfüllen völlig verschiedene Aufgaben, deswegen sind das keine Alternativen. Genausogut könntest du eine quicksort-Funktion mit einer printf-Funktion vergleichen..

    Den Vergleich versteh ich jetzt wirklich nicht. Ausserdem machen die Funktionen foo() wirklich das gleiche, sie rufen nämlich bar() auf.

    Christoph schrieb:

    Der Zeitaufwand ein Objekt zu konstruieren kann von vernachlässigbar bis immens reichen. Das hängt davon ab, wie aufwändig der Konstruktor ist. In einem konkreten Fall kannst du das nur sicher feststellen, indem du die Zeit misst. In deinem Fall dürfte der Aufwand wahrscheinlich vernachlässigbar sein.

    Deswegen habe ich ja geschrieben, dass die Klasse nur die Methode bar() implementiert und keinen fetten Konstruktor hat.

    Was mir weiterhilft ist sowas wie:
    Einfache Integeroperation: 10 hoch -8 s
    Klassengerüst instanzieren: 10 hoch -7 s
    COM Klasse irgendwas: 10 hoch -6 s
    (auf P4 2,8 GHz, ungefähre Werte)
    Da muss es doch irgendwo Tabellen dazu geben. Ich hab leider nichts gefunden.



  • electron schrieb:

    Christoph schrieb:

    Diese beiden Funktionen erfüllen völlig verschiedene Aufgaben, deswegen sind das keine Alternativen. Genausogut könntest du eine quicksort-Funktion mit einer printf-Funktion vergleichen..

    Den Vergleich versteh ich jetzt wirklich nicht. Ausserdem machen die Funktionen foo() wirklich das gleiche, sie rufen nämlich bar() auf.

    Wenn zwei das gleiche machen, ist das noch lange nicht das gleiche 😉 Die erste Version ruft immer das bar() des selben Objekts auf, die zweite jedes Mal das bar() eines neuen Objekts:

    class Test
    {
      int i;
    public
      Test():i(0){}
      int bar()
      { return ++i; }
    };
    
    Test x;
    void func1()
    {
      cout<<x.bar()<<endl;
    }
    
    void func2()
    {
      Test x;
      cout<<x.bar()<<endl;
    }
    
    int main()
    {
      for(int i=0;i<10;++i)func1();
      for(int i=0;i<10;++i)func2();
    }
    

    PS: Ich glaube kaum, daß sich jemand die Mühe gemacht hat, sowas auszumessen - aber du kannst das gerne übernehmen, wenn du nichts besseres zu tun hast 😉



  • electron schrieb:

    Christoph schrieb:

    Diese beiden Funktionen erfüllen völlig verschiedene Aufgaben, deswegen sind das keine Alternativen. Genausogut könntest du eine quicksort-Funktion mit einer printf-Funktion vergleichen..

    Den Vergleich versteh ich jetzt wirklich nicht. Ausserdem machen die Funktionen foo() wirklich das gleiche, sie rufen nämlich bar() auf.

    Beide Funktionen rufen zwar bar() auf, aber sie machen etwas völlig anderes. Die erste Funktion behält zwischen mehreren Aufrufen ihren Status, während die zweite Funktion nach dem Zurückkehren ihren Status vergisst. Diese beiden Funktionen sind also keine Alternativen, sondern führen tatsächlich zu unterschiedlichen Ergebnissen. Welche Variante man braucht, hängt vom aktuellen Problem ab.

    electron schrieb:

    Christoph schrieb:

    Der Zeitaufwand ein Objekt zu konstruieren kann von vernachlässigbar bis immens reichen. Das hängt davon ab, wie aufwändig der Konstruktor ist. In einem konkreten Fall kannst du das nur sicher feststellen, indem du die Zeit misst. In deinem Fall dürfte der Aufwand wahrscheinlich vernachlässigbar sein.

    Deswegen habe ich ja geschrieben, dass die Klasse nur die Methode bar() implementiert und keinen fetten Konstruktor hat.

    Was mir weiterhilft ist sowas wie:
    Einfache Integeroperation: 10 hoch -8 s
    Klassengerüst instanzieren: 10 hoch -7 s
    COM Klasse irgendwas: 10 hoch -6 s
    (auf P4 2,8 GHz, ungefähre Werte)
    Da muss es doch irgendwo Tabellen dazu geben. Ich hab leider nichts gefunden.

    Diese Faktoren hängen auf heutigen Architekturen leider von viel zu vielen Nebenbedingungen ab, als dass man eine solche Tabelle aufstellen könnte. Selbst wenn das jemand messen würde, würden die Ergebnisse nur für seinen Rechner für ganz bestimmten Code und für einen ganz bestimmten Compiler stimmen.

    Wie ich vorhin geschrieben habe: Eine Operation "Klassengerüst instanzieren" kann man überhaupt nicht abschätzen, weil die zwischen ~0ms und vielen Tagen liegen kann. Bei Klassen ohne komplizierten Konstruktor wird der Aufwand zum Konstruieren gegen 0 tendieren. Bevor ich mir um diese Handvoll Mikro- oder sogar Nano-Sekunden Gedanken mache, messe ich lieber mit einem Profiler wo die wirklichen Flaschenhälse liegen.

    Eine ungefähre Idee des Konstruktions-Aufwands bekommst du übrigens, wenn du dir den generierten Assembler-Code anschaust. Wenn das Objekt nur einen kleinen Konstruktor hat, wird zur Konstruktion wahrscheinlich nichtmal eine Funktion aufgerufen.



  • ...ich versuch mal einen anderen Ansatz. So komm ich nicht weiter.

    1.
    //Global
    CKlasse myclass;
    
    void foo()
    {
       myclass.bar();
    }
    
    2.
    void foo()
    {
       CKlasse myclass;
       myclass.bar();
    }
    

    Aussage1: Man sollte besser 1. implementieren, da es schneller ist.
    Frage: Gibt es dazu Artikel im Netz, die dieses Problem beschreiben? Hat jemand einen Link?

    Aussage2: COM ist eine langsame Thechnologie.
    Frage: Gibt es dazu Artikel im Netz, die dieses Problem beschreiben und evtl mit irgendwelchen Zahlen belegen? Hat jemand einen Link?

    Ansonsten Danke für die Antworten.
    Ach Christoph, jetzt hab ich deine 2. Antwort gesehen. Sowas in der Richtung habe ich gesucht. 😉 Vielleicht noch etwas ausführlicher. Dazu einen Bericht, Artikel, Infoseite....irgendetwas. Danke



  • Miss doch selbst nach! Wenn du keine Messungen durchgeführt hast, betreibst du vermutlich ohnehin extrem sinnlose und schädliche µOptimierung. Lass so was sein und investiere deine Zeit lieber vernünftig.

    Ansonsten hängt das eben vom Konstruktor ab. Hat die Klasse keinen Konstruktor, ist der Aufwand ja auch nicht viel größer als das anlegen einer Variable... Wenn der Konstruktor irgend welche RSA-Primzahlen faktorisiert, dauert es natürlich entsprechend lange...

    Und wie Christoph schon gesagt hat, sind heute Architekturen viel zu komplex, als das man noch sagen kann, was wie lange dauert!



  • electron schrieb:

    Aussage1: Man sollte besser 1. implementieren, da es schneller ist.

    1. ist theoretisch performanter, weil im Gegensatz zu 2. nicht bei jedem Funktionsaufruf ein neues Objekt erzeugt und wieder zerstört werden muss.



  • Ein Konstruktor, der nichts macht, macht nichts 😃 . Wenn Du keinen Konstruktor definierst oder einen Konstruktor in der Klassendefinition, der nichts macht, dann ist das ein no-op und daher kostenlos.

    Wenn die Konstruktion der Klasse Zeit kostet, dann ist es natürlich billiger, das einmal zu machen, statt mehrmals. Aber das ist eigentlich so sinnfrei, daß es schon fast peinlich ist, das überhaupt zu erwähnen 🙄 . Wie viel billiger die Variante 1 dann ist, hängt davon ab, wie lange der Konstruktor im vergleich zur Ausführung der Methode benötigt. Das Ergebnis ist im Zweifellsfall 42.



  • electron schrieb:

    Aussage1: Man sollte besser 1. implementieren, da es schneller ist.
    Frage: Gibt es dazu Artikel im Netz, die dieses Problem beschreiben? Hat jemand einen Link?

    Es sind 2 unterschiedliche Sachen.

    Nehmen wir ein konkretes Beispiel:

    //komplexe klasse zum darstellen grosser bilder
    class Image {
    //...
    };
    
    Image img("grossesbild.bmp");
    
    void foo1() {
       img.langwieriges_bearbeiten();
    }
    
    void foo2() {
       Image img("anderesbild.bmp");
       img.langwieriges_bearbeiten();
    }
    

    Nun erkennt man deutlich: die beiden funktionen machen etwas komplett anderes.
    foo2 erstellt ein image objekt, berechnet etwas und schmeisst das objekt wieder weg.

    sobald du sagen kannst: foo1 und foo2 machen das gleiche, ist deine Design kaputt. denn dann arbeitest du nicht mit objekten sondern klassen.

    aber ja: foo1 ist schneller - denn es muss kein bild erstellt werden. genauso kann ich aber auch sagen: es ist schneller mit dem rad zur arbeit zu fahren als jedesmal mir ein neues auto zu bauen bevor ich mit dem auto zur arbeit fahre.

    Aussage2: COM ist eine langsame Thechnologie.
    Frage: Gibt es dazu Artikel im Netz, die dieses Problem beschreiben und evtl mit irgendwelchen Zahlen belegen? Hat jemand einen Link?

    die frage ist nicht: ist COM langsam, sondern die frage ist: was willst du machen?

    wenn du vernünftiges interop brauchst ohne auf .net zurückgreifen zu können und nur windows systeme als zielplattform hast. dann ist COM das einzig wahre. wenn du aber kein echtes prozess interop brauchst, sondern nur eine plugin architektur willst und da uU sogar zur compile time feststehen welche plugins man haben will, dann ist COM schrecklich langsam.

    Beispiel:
    von Berlin Tempelhof nach Berlin Tegel kann man fliegen oder mit dem Auto fahren. wenn man fliegt, hat man natürlich das problem mit dem gepäck, dann sind die uhrzeiten wann man fliegen kann nicht so flexibel und teuer ist es auch.

    wenn man mit dem auto fährt ist es deutlich besser. wenn ich nun aber statt nach Berlin Tegel lieber nach New York - JFK will, ist das auto wieder denkbar langsam. obwohl es doch im vorherigen szenario um soviel besser war.


Anmelden zum Antworten