AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Klasse oder Record auf sich selbst?

Ein Thema von hronny · begonnen am 17. Mär 2009 · letzter Beitrag vom 29. Mär 2009
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#11

Re: Klasse oder Record auf sich selbst?

  Alt 18. Mär 2009, 00:44
Zitat von Cyf:
Vielleicht liegt das jetzt an meinen Geschmack und die OOP-Fetischisten werden mich jetzt steinigen , aber ist zur Verwaltung von Bäumen nicht eine Klasse, die einen Zeiger auf den Root kapselt und als Aufbau des Baums Records die aufeinander Zeiger enthalten sinnvoller? Bei der Benutzung von außen (außerhalb dieser Klasse) hat man dann trotzdem nur mit einem schönen Interface der Klasse zu kämpfen, während sie innen organisiert sein kann, wie sie will, und innen erspart man sich den nicht unbeträchlichen Overhead, für jedes Element ein Objekt zu erzeugen.
Okay, ich steinige dann mal

Erstens: Ja, kannst du so machen - OOP beinhaltet auch Kapselung Im Grunde kannst du also in der Baum-Klasse machen was du willst, solange ich das Teil problemlos benutzen kann.

Allerdings wird es etwas komplizierter sein, die Baumstruktur mit den records zu schreiben da man ja an alle initialisierungen und konsistenzprüfungen denken muss.

Btw.: Ich würde gerne mal den "nicht unbeträchlichen Overhead für jedes Element ein Objekt zu erzeugen" sehen - wenn ich richtig informiert bin, stehen die Methoden der Klasse sowiso im Speicher herum. Wenn ein Objekt dann angelegt wird, passiert doch eigenlich nichts weiter, als dass ein Speicherbereich reserviert wird, in den dann der Self-Pointer, die Felder und vll. n paar Typinformationen reinkommen. Kommt dann natürlich noch drauf an, was im Konstruktor passiert.

Ist jetzt nicht bös gemeint oder so, aber ich wollte nur mal meinen Senf dazugeben
(Nein, es ist nicht der mittelscharfe von Develei ^^)
  Mit Zitat antworten Zitat
Cyf

Registriert seit: 30. Mai 2008
407 Beiträge
 
Lazarus
 
#12

Re: Klasse oder Record auf sich selbst?

  Alt 18. Mär 2009, 01:45
Naja beim erzeugen eines Objektes pasiert schon ein wenig mehr, als beim reservieren von Speicher für einen neuen Record auf dem Heap, bei Objekten müssen ja immer auch Zeiger und Informationen auf die (ja, einmalig, statisch angelegten) RTTI angelegt werden zwecks Methodentabelle etc.
Wenn du im Debugger allein mal den Aufruf von TObject.Create verfolgst, dann kommt in etwa sowas:

Code:
TObject.Create:
00403808 84D2             test dl,dl
0040380A 7408             jz $00403814
0040380C 83C4F0           add esp,-$10
0040380F E830030000       call @ClassCreate
00403814 84D2             test dl,dl
00403816 740F            jz $00403827
00403818 E87F030000       call @AfterConstruction
0040381D 648F0500000000   pop dword ptr fs:[$00000000]
00403824 83C40C          add esp,$0c
00403827 C3               ret

@ClassCreate:
00403B44 52               push edx
00403B45 51               push ecx
00403B46 53               push ebx
00403B47 84D2             test dl,dl
00403B49 7C03             jl $00403b4e
00403B4B FF50F4           call dword ptr [eax-$0c] //<- NewInstance
00403B4E 31D2             xor edx,edx
00403B50 8D4C2410         lea ecx,[esp+$10]
00403B54 648B1A          mov ebx,fs:[edx]
00403B57 8919             mov [ecx],ebx
00403B59 896908           mov [ecx+$08],ebp
00403B5C C741046D3B4000   mov [ecx+$04],$00403b6d
00403B63 89410C          mov [ecx+$0c],eax
00403B66 64890A          mov fs:[edx],ecx
00403B69 5B              pop ebx
00403B6A 59               pop ecx
00403B6B 5A              pop edx
00403B6C C3               ret

TObject.NewInstance:
004037D0 53               push ebx
004037D1 8BD8             mov ebx,eax
004037D3 8BC3             mov eax,ebx
004037D5 E826000000       call TObject.InstanceSize
004037DA E8B1F4FFFF      call @GetMem
004037DF 8BD0             mov edx,eax
004037E1 8BC3             mov eax,ebx
004037E3 E85C000000       call TObject.InitInstance
004037E8 5B              pop ebx
004037E9 C3               ret
004037EA 8BC0             mov eax,eax

TObject.InstanceSize:
00403800 83C0D8           add eax,-$28
00403803 8B00             mov eax,[eax]
00403805 C3               ret
00403806 8BC0             mov eax,eax

@GetMem:
00402C90 85C0             test eax,eax
00402C92 7E13             jle $00402ca7
00402C94 FF151C474500     call dword ptr [$0045471c]
00402C9A 85C0             test eax,eax
00402C9C 7402             jz $00402ca0
00402C9E F3C3             rep ret
00402CA0 B001             mov al,$01
00402CA2 E939010000       jmp Error
00402CA7 31C0             xor eax,eax
00402CA9 F3C3             rep ret
00402CAB 90               nop

TObject.InitInstance:
00403844 53               push ebx
//[...]
00403899 C3               ret

@AfterConstruction:
00403B9C 55               push ebp
//[...]
00403BC6 83C408           add esp,$08
00403BC9 EB19             jmp $00403be4
00403BCB E930010000       jmp @HandleAnyException
00403BD0 B201             mov dl,$01
00403BD2 8B45FC          mov eax,[ebp-$04]
00403BD5 E812000000       call @BeforeDestruction
00403BDA E8DD040000       call @RaiseAgain
00403BDF E82C050000       call @DoneExcept
//[...]
00403BE9 C3               ret
Beim Anfordern von Heap-Speicher für einen Record via New(aPointer) wird das ganze hingegen (solange keine Strings o. ä. beteiligt sind, dann kommt noch ein Initialize hinzu) zu nur einem GetMem. Das mag bei kleinen Datenmengen nicht ins Gewicht Fallen, aber lass es mal große Datenmengen sein, dann macht das prozentual schon etwas aus, auch wenn das praktisch nur dann spürbar sein sollte, wenn diese ständig neu erzeugt werden müssen (z.B. irgendwelche Listen über Objekte die ihren Zustand ändern).

Folgender Testcode:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  Timer: TQPCounter;
  i: Integer;
  p: PInteger;
begin
  Timer:= TQPCounter.Create; //eigene Klasse um die Zeit zu messen, unbedeutent
  for i := 0 to 9999999 do
  begin
    New(p);
    //oder: TObject.Create; über das memory Leak sei mal hinweggesehen, auch das Freigeben dauert beim Objekt länger
  end;
  Showmessage(Timer.ClockStr);
  Timer.Free;
end;
mit Zeiger: 240-330ms
mit Objekt: 670-690 ms

Wie weit das jetzt unter welchen Bedingungen spürbar ist, kann man sich streiten, das ist wahr, bloß der Code zum Verwalten des Baums muss sowieso irgendwo hin, ob jetzt in die Verwaltungsklasse, oder in die Nodes, ist dann egal, also nehm ich die schnellere Variante.
Natürlich gibt es bestimmt auch Situationen, wo die Klasse Sinn macht, etwa bei Kombinationen von verschiedenen Knotenarten, die irgendwie in Beziehung stehen und anders reagieren sollten.

[Edit]Zeiten mit Dispose bzw. mit Zuweisung des Objekts auf eine Variable und dann MyObj.Free:

leere Schleife: ca. 5,37 ms
Zeiger New und Dispose: ca. 150 ms (ja das ist weniger, liegt nicht an Auslastung im Hintergrund o. ä., habs mehrfach verglichen, es ist immer sehr viel weniger, vermute mal, weil nicht immer kleine Mengen Heap angefordert werden, sondern immer die selbe Stelle, die der Memory-Manager noch hält)
Objekt Create und Free: ca. 815 ms
Man kann einen Barbier definieren als einen, der alle diejenigen rasiert, und nur diejenigen, die sich nicht selbst rasieren.
Rasiert sich der Barbier?
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 16. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#13

Re: Klasse oder Record auf sich selbst?

  Alt 18. Mär 2009, 02:30
Zitat von Cyf:
Naja beim erzeugen eines Objektes pasiert schon ein wenig mehr...
Ich kann mir nur ganz wenige Dinge (also Record oder Objekt) vorstellen, bei dem der Overhead der Klasse wirklich ins Gewicht fällt.
Das wären z.B. Koordinaten (x,y) oder komplexe Zahlen (realteil und imaginärteil).
Also Dinge, die einerseits sehr kleine Informationsmengen enthalten und andererseits in hohen Stückzahlen von 100000 oder noch mehr gebraucht werden.
Dann hat ein Record einen spürbaren Performancevorteil gegenüber einer Klassse.
Ein Beispiel wäre ein Partikelsystem, in dem sehr viele kleine Partikel im virtuellen Raum herumfliegen.
Oder Strings - in manchen Progsprachen ist jeder String ein Objekt.
Hier hat Delphi ja seinen eigenen Weg gewählt.

Wenn Beides aber nicht zutrifft (also geringe Datenmenge und sehr hohe Stückzahl), dann ist der Overhead eines Objekt praktisch nicht spürbar.
Dann kann die OOP ihre Trümpfe ausspielen und wer geschickt programmiert brauchst sich um die Leistung keine Sorgen machen.
Manchmal erreicht man mit OOP sogar mehr Leistung also ohne.
Der Grund dafür ist, dass man mit OOP bestimmte Algorithmen verwenden kann (Objektcache, Nullobjekte, Hashing-Verfahren) die man ohne OOP nicht verwenden könnte ohne das der Sourcecode zu einem unwartbaren Klumpen würde.
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#14

Re: Klasse oder Record auf sich selbst?

  Alt 18. Mär 2009, 08:06
Wenn Performance das einzige Kriterium wäre, dann sollte man von OOP die Finger lassen. In der Tat werden viele der fundamentalen Datenstrukturen ohne OOP implementiert. Das liegt aber in erster Linie daran, das man die Vorzüge der OOP hier nicht braucht. Klar kommt noch der Performancefaktor ins Spiel.
Wenn du also eine Klasse für das Speichern von Bäumen schreiben willst, dann verwende ruhig Records für die Baumstruktur, um beim Einfügen von 1 Mio Knoten einen Geschwindigkeitsvorteil von 400ms zu haben (Nebenbei ist ein Baum keine sonderlich schnelle Datenstruktur).

Die Schnittstelle wird aber eh eine Klasse sein, da hier die OOP-Vorzüge (Stichwort: Erweiterbarkeit) zum Tragen kommen müssen, und sei es, die Methode des Schlüsselvergleiches (ComapareString, CompareText, etc.) verändern zu können.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
hronny

Registriert seit: 4. Mai 2006
Ort: Thüringen
97 Beiträge
 
Delphi 2007 Professional
 
#15

Re: Klasse oder Record auf sich selbst?

  Alt 29. Mär 2009, 22:20
Ich habe da es nicht 100000 Datensätze sind, jedenfalls mit OOP gelöst und es klappt super.
grep -ri shit /usr/src/linux/*
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz