Wieviel Performance kostet die Objekt orientierte Programmierung?



  • Objektorientierung kostet grundsätzlich gar nichts.



  • Wer tritt mit einer objektorientieren Version von einem einfachen Schiffe versenken gegen meine nicht objektorientiere Version an?

    Es müssen die gleichen Algorithmen zum platzieren und schiessen verwendet werden! Es geht nicht darum einen besseren Schiess-Algo zu bauen, sondern nur um den Vergleich objektorient vs. nicht objektorient.

    Feldgröße: 10x10
    Schiffe: 1x5, 2x4, 3x3, 2x2

    Plaziert wird zufällig, bis eine freie Stelle gefunden wurde. Schiffe werden nur horizotal platziert. Schiffe dürfen die Feldbegrenzung nicht überschreiten und sich nicht überlagern.

    Geschossen wird immer zufällig bis alle Schiffe versenkt sind.

    Damit die Ergebnisse vergleichbar sind, wird bei Programmstart mit srand(8); initialisiert.
    Am Ende sollte bei beiden Versionen die gleiche Anzahl an rand() aufrufen gebraucht werden.

    Gemessen werden 1000000 Durchgänge mit platzieren und schießen.

    #include <iostream>
    #include <stdlib.h>
    #include <vector>
    #include <iomanip>
    #include <ctime>
    
    using namespace std;
    
    const int fieldSize = 100;
    const int fieldWidth = 10;
    
    const int NOSHIP = -1;
    
    int randCount = 0;
    
    int gameRand()
    {
    	randCount++;
    	return rand() % fieldSize;
    }
    
    void dumpField( vector<int> & field, vector<int> & ships)
    {
    	for( size_t i = 0; i<fieldSize; i++ )
    	{
    		if ( i%fieldWidth == 0 )
    		{
    			cout << endl;
    		}
    		cout << setw(2) << field[i] << " ";
    	}
    	cout << endl;
    	for( size_t i = 0; i<ships.size(); i++ )
    	{
    		cout << i << ": " << ships[i] << endl;
    	}
    }
    
    void placeShips( vector<int> & field, vector<int> & ships, vector<int> const& shipSizes )
    {
    	for( size_t shipNum = 0; shipNum<shipSizes.size(); )
    	{
    		size_t pos = gameRand() % fieldSize;
    		int free = 0;
    		int x = pos%fieldWidth;
    		for( size_t s = 0; pos+s < fieldSize && x+s<fieldWidth && s < shipSizes[shipNum]; s++ )
    		{
    			if ( field[pos+s] != NOSHIP )
    			{
    				break;
    			}
    			free++;
    			field[pos+s]=shipNum;
    		}
    		if ( free==shipSizes[shipNum] )
    		{
    			ships[shipNum]=shipSizes[shipNum];
    			shipNum++;
    		}
    		else
    		{
    			//reset
    			for( size_t s = 0; s < free; s++ )
    			{
    				field[pos+s] = NOSHIP;
    			}
    		}
    	}
    }
    
    int main(void)
    {
    	srand(8);
    
    	vector<int> shipSizes;
    	shipSizes.push_back(5);
    	shipSizes.push_back(4);
    	shipSizes.push_back(4);
    	shipSizes.push_back(3);
    	shipSizes.push_back(3);
    	shipSizes.push_back(3);
    	shipSizes.push_back(2);
    	shipSizes.push_back(2);
    
    	vector<int> ships(shipSizes.size());
    
    	clock_t start = clock();
    
    	for( int i = 0; i<1000000; i++ )
    	{	
    		int remainingShips = shipSizes.size();
    		vector<int> field(fieldSize, NOSHIP);
    
    		placeShips( field, ships, shipSizes );
    
    //		cout << "begin\n";
    //		dumpField( field, ships );
    
    		while ( remainingShips > 0 )
    		{
    			int shotPos = gameRand();
    			int shipNr = field[shotPos];
    			if ( shipNr > NOSHIP )
    			{
    				ships[shipNr]--;
    				if( ships[shipNr]==0 )
    				{
    					remainingShips--;
    				}
    //				cout << "At: " << shotPos <<"\n";
    //				dumpField( field, ships );
    				field[shotPos] = NOSHIP;
    			}
    		}
    
    //		dumpField( field, ships );
    	}
    
    	clock_t end = clock();
    
    	cout << "RandCount " << randCount << "\nTime: " << end-start << endl;
    }
    


  • PS: Nur class um meinen Code zu schreiben zählt nicht als objektorient.



  • Wer tritt mit einer ...

    Zeitverschwendung.



  • @Herausforderer
    Und was erwartest du von dem Code? Da kann man vielleicht 3 Klassen einbauen:
    - Random generator
    - Ship
    - Field
    Wobei aber keine interessanten Eigenschaften oder sonst etwas vorhanden sind. Die Random Generator Klasse funktioniert genau so wie deine jetzige Funktion. Die Schiff Klasse ist ja nichts anderes als eine Größenangabe und Field bleibt ein Wrapper um std::vector, mit Konstruktor und shoot Methode.

    Klar, das sieht dann alles etwas schöner aus. Aber um ernsthaft einen Vorteil aus der Objektorientierung zu bekommen ist das Programm viel zu unkomplex. Die Random Funktion packst du in die Generator-Klasse. Ship hält einfach eine Größenangabe. Die placeShips Funktion wird zum Field Konstruktor und Teil deines Hauptloops wird halt zu Field::shootOn(unsigned Position);
    Du siehst also, abgesehen davon dass man hier eh vor allem die Performance von rand() misst, wird da genau das gleiche Ergebnis rauskommen.



  • Objektorientiert programmieren bedeutet ja nicht, nur ein paar Getter und Setter für meine Arrays zu machen, sondern ein Klassendesign mit Kapselung zu haben und OO Pattern zu verwenden, also z.B. Observer für Schuss-Events oder ähnliches verwenden.

    So wie ich es gemacht habe ist doch garnichts objektorientiert und gekapselt. Bei einem OO Design macht man doch nicht ein paar Zahlen in ein Spielfeld-Array um die Positionen der Schiffe zu speichern. Bei einem OO Design würde man doch wohl eher sowas machen, dass das Schiff seine Größe und Position kenn und weiß wo es getroffen wurde. Überlegt euch einfach mal, wie ihr sowas objektorientiert designen würdet, ohne an meinen Code zu denken.

    Das rand() möglicherweise am meisten Zeit brauchen könnte, habe ich auch schon befürchtet, aber dann kann man ja ein schnelleres rand verwenden.



  • Herausforderer schrieb:

    Das rand() möglicherweise am meisten Zeit brauchen könnte, habe ich auch schon befürchtet, aber dann kann man ja ein schnelleres rand verwenden.

    Das geht erstaunlicherweise noch, es braucht "nur" 50% der Zeit.

    Und nein, objektorientiert zu programmieren bedeutet nicht, irgendwelche Pattern von Wikipedia zu kopieren und zur Lösung eines nicht existenten Problems einzusetzen. Wenn die Schiffe irgendwie selbstständig wären, agieren könnten, eventuell eine KI bräuchten, verschiedene Eigenschaften etc. hätten, dann würde es langsam spannend. So ist es einfach nur ein gepunktetes Feld, in diesem Sinne ist auch dein Code bereits Objektorientiert, du hast nur kein class um dein Feld und freie Funktionen statt Methoden. Aber dein Feld ist trotzdem ein Objekt - und deine Funktionen können auf diesem agieren. Ha! Da musst du dich schon mehr anstrengen, um der Objektorientierung zu entkommen. :xmas1:

    Und genau deshalb macht deine Frage so wenig Sinn. Objektorientierung ist halt erst mal nur eine Sichtweise, das beschreibt keinen konkreten Implementierungsweg. Wenn du meckern willst, dann nenne irgendein Konzept das du für sinnlos erklärst. 😉



  • OOP & Performance schrieb:

    Wieviel Performance kostet die Objekt orientierte Programmierung?

    Wie volkard schon gesagt hat, hängt das von der Sprache bzw. ganz konkret vom jeweiligen Compiler ab. Objektorientierung ist etwas für den Programmierer und nicht für den Prozessor. Der Compiler kann daraus machen, was er will. Wie viel von der Objektorientierung im kompilierten Programm noch zu erkennen ist, ist nicht festgelegt.

    Abgesehen davon geht es bei der Objektorientierung nicht um Performance, sondern darum, dass komplexer Code beherrschbar und wartbar bleiben soll. Wie gesagt: Es ist eine Sache für den Programmierer. Wenn Du die Vorteile von OOP testen möchtest, dann musst Du ein größeres Programm (einige 10.000 Zeilen) einmal objektorientiert und einmal rein prozedural, programmieren. Und dann musst Du Vergleichen, wie hoch der Zeitbedarf beim Programmieren war, wie viele Fehler noch drin sind, wie gut Du den Code jeweils lesen kannst und so weiter.

    Performance ist eine Frage von ganz kleinen Codebereichen in einem Programm. Jeder kennt die 90-10 Regel "90% der Zeit wird in 10% des Codes verbracht". Wobei das vermutlich eher eine 97-3 Regel ist. Wenn man ein Performanceproblem hat, dann schaut man sich ganz genau die kleinen Codebereiche an, die dafür verantwortlich sind. Und dann kann man sich immer noch überlegen, ob in dem Zusammenhang irgendein objektorientiertes Konstrukt der Übeltäter ist und man diesen kleinen Codebereich bezüglich Performance optimieren sollte.



  • cooky451 schrieb:

    So ist es einfach nur ein gepunktetes Feld, in diesem Sinne ist auch dein Code bereits Objektorientiert, du hast nur kein class um dein Feld und freie Funktionen statt Methoden. Aber dein Feld ist trotzdem ein Objekt - und deine Funktionen können auf diesem agieren. Ha! Da musst du dich schon mehr anstrengen, um der Objektorientierung zu entkommen. :xmas1:

    Wenn du so objektorientiert programmierst, dann programmierst du nicht objektorientiert. Das ist nicht nur ein gepunktetes Feld. Gerade vorher wolltest du noch zwei Klassen Field und Ship machen. Jetzt willst du praktisch nur noch eine Klasse Game machen und alles in diese werfen.

    Wenn du meckern willst, dann nenne irgendein Konzept das du für sinnlos erklärst. 😉

    Ich will nicht meckern. Ich würde nie ein größeres Projekt nicht objektorientiert machen, aber ich glaube schon, dass objektorientierte Programme meistens langsamer sind, weil man anders designt, dafür aber meistens auch flexibler ist.


  • Mod

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider. Aber nicht so großer Quark wie von dem Herausforderer, der mit allen Mitteln versucht, sich seine Welt so zu verbiegen, wie es ihm passt.

    Es kann technische Nachteile geben bei dem Code der von typischen objektorientierten Ansätzen erzeugt wird.



  • Eins euro fufzik



  • SeppJ schrieb:

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider. Aber nicht so großer Quark wie von dem Herausforderer, der mit allen Mitteln versucht, sich seine Welt so zu verbiegen, wie es ihm passt.

    Es kann technische Nachteile geben bei dem Code der von typischen objektorientierten Ansätzen erzeugt wird.

    Des Herausforderers "nicht objektorientierte" Version dürfte als einzigen Schwachpunkt haben, den der optimierende Compiler nicht sieht, daß der vector dauernd neu angelegt und gelöscht wird. Also ausgerechnet sein Versuch, doch ein wenig OO zu programmieren.



  • SeppJ schrieb:

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider.

    cooky451 schrieb:

    Objektorientierung ist halt erst mal nur eine Sichtweise, das beschreibt keinen konkreten Implementierungsweg. Wenn du meckern willst, dann nenne irgendein Konzept das du für sinnlos erklärst. 😉

    Und genau deshalb ist dein Post Quark, SeppJ, und nicht meiner.



  • Wenn ich nur von einer Sichtweise spreche, kann ich aber auch nicht von Performance sprechen.
    Ich muss von einer Implementierung sprechen, um über Performance zu diskutieren - und dann kostet OOP unter Umständen (richtig, Programmierung. Nicht Analyse, nicht Design. Programmierung).

    Absolute statements...:)



  • volkard schrieb:

    SeppJ schrieb:

    314159265358979 schrieb:

    Objektorientierung kostet grundsätzlich gar nichts.

    Quark, mal wieder, leider. Aber nicht so großer Quark wie von dem Herausforderer, der mit allen Mitteln versucht, sich seine Welt so zu verbiegen, wie es ihm passt.

    Es kann technische Nachteile geben bei dem Code der von typischen objektorientierten Ansätzen erzeugt wird.

    Des Herausforderers "nicht objektorientierte" Version dürfte als einzigen Schwachpunkt haben, den der optimierende Compiler nicht sieht, daß der vector dauernd neu angelegt und gelöscht wird. Also ausgerechnet sein Versuch, doch ein wenig OO zu programmieren.

    Das Erstellen und Füllen des vectors kann man aus der Schleife raus nehmen, am Ende ist der vector sowieso wieder so gefüllt wie am Anfang. Bringt aber nur so ca. 7%.

    Wenn ihr meint, dass meine Version objektorientiert ist, wie sieht dann eine nicht objektorientierte Version aus?



  • Herausforderer schrieb:

    Wenn ihr meint, dass meine Version objektorientiert ist, wie sieht dann eine nicht objektorientierte Version aus?

    Genau so. Es ist eine verdammte Sichtweise!! 😃



  • [quote="cooky451"]

    OOP & Performance schrieb:

    Wieso kostet es in C++ nichts?

    Weil aus

    class A
    {
      float value_;
    public:
      A(float value)
        : value_(value)
      {}
      float &value()
      {
        return value_;
      }
    };
    
    int main()
    {
      A a(534.65f);
      std::cout << a.value();
      getchar();
    }
    

    das da wird:

    012D14A0  fld         dword ptr [__real@4405a99a (12EA0D8h)]  
    012D14A6  push        ecx  
    012D14A7  fstp        dword ptr [esp]  
    012D14AA  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (12D1550h)
    

    [QUOTE]

    Damit ist die Datenkapselung aber fürn Arsch:

    #include <iostream>
    #include <stdio.h>
    
    class A
    {
      float value_;
    public:
    
      A(float value)
        : value_(value)
      {}
    
      float &value()
      {
        return value_;
      }
    };
    
    int main()
    {
      A a(534.65f);
      std::cout << a.value();
      float* d = &a.value(); // Oh je...
      *d = 10; // Damit ist die Datenkapselung fürn Arsch
      std::cout << std::endl << *d;
      std::cout << std::endl << a.value(); // LOL
      getchar();
    }
    

    Zudem solltest du mal beschreiben, was genau du mit Objektorientierung meinst. Ist FILE* aus C eine Klasse? Was schlägst du als Alternative vor?

    Die Datenkapselung und das Geheimnisprinzip sollte schon aufrecht erhalten bleiben.
    OOP heißt, daß eine andere Person die Implementierung der Objektdaten und Objektmethoden nicht kennen muß, alles was er kennen darf, sind die Deklarationen der public Methoden und public Objektvariablen.
    Also die Schnittstellen zu dem Objekt.

    D.h. also, wenn er seinen Code so wie hier bei

    float* d = &a.value();
    

    programmiert, dann fliegt der Code mächtig auf die Schnauze, wenn die Klasse intern irgendwann während der Softwareentwicklung verändert wird.

    Deswegen gibt es das Prinzip der Datenkapselung und dem Geheimnisprinzip, sowie der maximalen Entkopplung.

    Dein Code ist also zwar vielleicht schnell, aber er erfüllt die Bedingungen der OOP nicht mehr.
    Da kann man das ganze Klassenkonstrukt auch gleich weglassen.



  • Dann gleich noch eine Frage.

    Wieso heftest du den Adressoperator an den Funktionsnamen und nicht an den Rückgabetyp, so wie es IMO sein sollte?

    cooky451 schrieb:

    float &value()



  • Hehe jo, du hast in völlig zusammenhangslosem Beispielcode einen imaginären Schönheitsfehler gefunden. 👍
    Dass der resultierende Binärcode völlig identisch mit der "nicht Referenz"-Version bleibt, dürfte wohl klar sein.

    Pfusch schrieb:

    Wieso heftest du den Adressoperator an den Funktionsnamen und nicht an den Rückgabetyp, so wie es IMO sein sollte?

    Deswegen: http://ideone.com/NGNYG
    Ich würde Referenzen und Pointer auch lieber dem Datentypen zuschreiben. Das Komitee selbst scheint sich ja nicht mal ganz einig über die Schreibweise zu sein. Früher standen */& beim Variablennamen, jetzt stehen sie öfter beim Typ. Einheitlich machen sie es jedenfalls nicht, von daher zählt für mich vor allem die Eigenschaft von oben.



  • cooky451 schrieb:

    Hehe jo, du hast in völlig zusammenhangslosem Beispielcode einen imaginären Schönheitsfehler gefunden. 👍

    kleine schönheitsfehler, wenn man jenen überhaupt so nennen will, find ich super 👍


Anmelden zum Antworten