Optimierung Klassenaufruf

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von raist10.

    Optimierung Klassenaufruf

    In einem meiner Projekte habe ich eine Datenbankklasse angelegt (Name= dtb)
    Sie ist dazu da, die Verbindung zu einer Oracle-Datenbank zu erstellen,
    sowie etliche Funktionen wie Zeilenzählen, Parameter ändern, Parameter löschen
    usw. bereit zu stellen.
    Ich habe den Code an meinem Arbeitsplatz, darum hier nur Pseudocode
    Beispielsweise die Anzahl der Einträge in der Userdatenbank in der Anmeldenamen_Tabelle:

    Anzahl_Eintraege= dtb.zeilencount(dtb.Verbindung(User_verbindung), dtb.Tabellenname(Anmeldenamen))

    Nun ist es so, wenn ich per Debugger durch meinen Code steppe, so wird natürlich für jede der
    aufgerufenen Funktionen (dtb.Verbindung, dtb.Tabellenname) die Klasse einzeln angesprochen.

    Meine Frage ist nun: Ist meine Vorgehensweise überhaupt performance-optimal, oder habe ich da
    einen Aufbaufehler, oder wirkt sich das im compilierten Programm nicht aus, weil der Compiler
    sich selbst eventuell ein Stack erstellt, um gerade benutzte Sprungadressen zu cachen?

    Ich hoffe ich habe mich klar ausgedrückt. Ich finde es halt nicht besonders performant, dass
    die Klasse laufend wieder neu angesprochen wird.
    Das Ansprechen von Methoden über Klasseninstanzen gehört in OOP-Sprachen dazu. Deshalb ist das Performance-mäßig sehr optimiert (afaik ist das unter .NET fast so schnell wie ein Zeigerzugriff in Native C++). Viel mehr würde ich mir darüber Gedanken machen, was man an meinem Code optimieren könnte (Doppelter Zugriff auf DB?, Vorkompilierte Serverprozedur?).

    Viele Grüße, Phil.

    YaPh1l schrieb:

    (Doppelter Zugriff auf DB?, Vorkompilierte Serverprozedur?).

    Viele Grüße, Phil.

    Was meinst du mit Doppelter Zugriff?

    Serverprozedur?
    Ich verwende natürlich COUNT, um die Anzahl der Zeilen abzurufen, muss ja aber der Klasse die Verbindungsdaten
    und den Tabellennamen übergeben. Ich versuche so weit wie möglich SQL zu verwenden.
    Natürlich könnte ich auch für alle meine Verbindungen eigene Klassen verwenden
    das würde Aufrufe sparen, hatte mich aber dafür entschieden alles über eine zentrale Klasse zu verwalten.
    Danke,
    zumindest bin ich jetzt beruhigter, dass es wohl weniger am Datenbankzugriff liegt.

    Hauptproblem dürfte sein, dass ich es nicht geschafft hatte, bei meinem etwas komplexen
    System auf Databinding zu setzen.

    Ich hatte es irgendwo im Forum schon erwähnt...
    Ein DataGridView, das teilweise verschiedene Zeilenfarben, und teilweise normale und fette
    Schrift benötigt, und das alles abhängig von unteren und oberen Grenzwerten der Zahlen
    die ich dort eintragen muss. Spalten die man verschieben muss, einzelne Zellen abhängig
    von anderen Enträgen, ob man diese editieren darf usw. Und das bei meinem ersten
    größeren VB-Net Projekt.

    Lightsource schrieb:

    Beispielsweise die Anzahl der Einträge in der Userdatenbank in der Anmeldenamen_Tabelle:

    Anzahl_Eintraege= dtb.zeilencount(dtb.Verbindung(User_verbindung), dtb.Tabellenname(Anmeldenamen))

    Nun ist es so, wenn ich per Debugger durch meinen Code steppe, so wird natürlich für jede der
    aufgerufenen Funktionen (dtb.Verbindung, dtb.Tabellenname) die Klasse einzeln angesprochen.

    Meine Frage ist nun: Ist meine Vorgehensweise überhaupt performance-optimal, oder habe ich da
    einen Aufbaufehler, oder wirkt sich das im compilierten Programm nicht aus, weil der Compiler
    sich selbst eventuell ein Stack erstellt, um gerade benutzte Sprungadressen zu cachen?

    Ich hoffe ich habe mich klar ausgedrückt. Ich finde es halt nicht besonders performant, dass
    die Klasse laufend wieder neu angesprochen wird.



    Wenn die Klasse instanziert ist, dürfte es keinerlei Auswirkung auf die Performance haben. Aber das wurde ja schon ausgeführt.

    Ich würde nur den Aufbau dieses Beispiels-Code anders gestalten. Was aber weniger mit Performance sondern eher mit Übersichtlichkeit/Kapselung zu tun hat.

    Ich bevorzuge für Aufrufe die aus einer Klasse mehrere Eigenschaften abfragen oder Methoden zu einem einzigen Return zusammen fassen, eher die Konstellation eine eigene Klasse zu erstellen die die Zugriffsklasse erbt und dort die Methode einmalig zu schreiben. Wäre auch sauberer von der Konstruktion her.

    Dann könntest Du überall im Code den Aufruf einfacher schreiben:

    dtbAcc.Anzahl_Eintraege

    Wobei ich jetzt die Parent-Klasse mal mit dtbAcc bezeichnet habe und diese erbt von dtb.

    VB.NET-Quellcode

    1. Public Class dtbAcc
    2. Inherits dtb
    3. Public Function Anzahl_Eintraege() As Int32
    4. ' hier könnte noch eine Prüfung ob überhaupt DB Verbindung besteht erfolgen
    5. Return zeilencount(verbindung(user_Verbindung), tabellennamen(Anmeldenamen))
    6. End Function
    7. End Class


    Dadurch kannst Du auch sauberer kapseln (Du musst halt nicht alles öffentlich machen, sondern durch Ansprache der oberen Aufrufebene kannst Du viele Methoden/Eigenschaften der unteren Aufrufebene per Protected verbergen ... macht es übersichtlicher und besser wartbar) und auch Prüfroutinen/Fehlerabfang dort einbauen anstatt bei jeder Nutzung einzeln daran denken zu müssen. Mal davon abgesehen ergeben sich auch Vorteile wenn Du unmanaged Ressourcen handeln musst, einfach IDisposable Interface in der oberen Aufrufebene einbauen und dann per Using/End Using in jedem weiteren Code ansprechen/verwenden.

    Nur mal so als Idee/Überlegung.

    Gruß

    Rainer

    Lightsource schrieb:

    Ein DataGridView, das teilweise verschiedene Zeilenfarben, und teilweise normale und fette
    Schrift benötigt, und das alles abhängig von unteren und oberen Grenzwerten der Zahlen
    die ich dort eintragen muss. Spalten die man verschieben muss, einzelne Zellen abhängig
    von anderen Enträgen, ob man diese editieren darf usw. Und das bei meinem ersten
    größeren VB-Net Projekt.

    da fällt mir ein - zu gestylten Grids: guggemal die Bildchen auf DGV-Screenies
    @raist10:
    Ich verstehe was du meinst, aber ich frage mich dann wie der Compiler so etwas handhabt.
    Werden auf diese Weise nicht zusätzliche Daten und Rücksprungadressen auf den PC_Stack gelegt?
    Natürlich glaube ich, dass das Ganze übersichtlicher und wartbarer wird.

    @ErfinderDesRades:
    Die DataGrids sehen ganz gut aus.

    Aber nehmen wir mal folgende Vorgabe:
    Ich habe mehrere Produkte, die ich durch verschiedene Hintergrungfarben der Zeilen
    klarer dargestellt haben will. Ich lese also die Spalte, in der die Produktnummer steht
    und schaue in einer entsprechenden Tabelle, in der der Farbkode steht (per SQL)
    daraufhin ändere ich die Hintergrundfarbe der betroffenen Zeile.

    Wie machst du das durch Datenbinding?
    @raist10:
    Ich verstehe was du meinst, aber ich frage mich dann wie der Compiler so etwas handhabt.
    Werden auf diese Weise nicht zusätzliche Daten und Rücksprungadressen auf den PC_Stack gelegt?
    Natürlich glaube ich, dass das Ganze übersichtlicher und wartbarer wird.

    Doch, wird natürlich per Adressen gehandhabt, wodurch auch das hier:

    VB.NET-Quellcode

    1. Function Getbla() As String
    2. Return "bla"
    3. End Function
    4. MsgBox(GetBla())

    langsamer ist als:

    VB.NET-Quellcode

    1. MsgBox("bla")

    Aber trotzdem gehört es zum guten Stil, sonst könntest du gleich BASIC Like programmieren, aber am besten noch ohne GoSub und Return bzw. auch ohne Goto, schließlich muss dazu ja erst an die Adresse gesprungen werden...xD :P
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    Lightsource schrieb:

    Ich habe mehrere Produkte, die ich durch verschiedene Hintergrungfarben der Zeilen
    klarer dargestellt haben will. Ich lese also die Spalte, in der die Produktnummer steht
    und schaue in einer entsprechenden Tabelle, in der der Farbkode steht (per SQL)
    daraufhin ändere ich die Hintergrundfarbe der betroffenen Zeile.
    Ja, und was machst du, wenn einer auf den Spaltenkopf klickt, und dadurch die Produkte neu sortiert werden, mw. nach Lieferant? Dann haben ja die DGV-Zeilen immer noch die Farben, die ihnen per SQL-Abfrage zugewiesen wurden - es stehen aber andere Produkte in den Zellen!
    Oder startest du dann immer eine neue DB-Abfrage?
    Das ist aufwändig zu proggen, und bedeutet unnötigen DB-Traffic.
    Das Aufwändige ist, du mußt den Farbabgleich jedesmal erneuern beim Befüllen, Umsortieren, Filtern - in manchen Anwendungsfällen sogar bei jedem Ändern der Daten.

    Wie machst du das durch Datenbinding?
    Ich erledige das einheitlich an genau einer Stelle, nämlich im DGV-CellPainting. Dort hole ich mir aus der BindingSource den Datensatz der zu zeichnenden Zelle, und zeichne entsprechend den Background (alles andere lasse ich weiterhin das DGV zeichnen: Gridlines, FocusRect, Content, SelectedContent ...)

    Auf diese Weise kannst du Umsortieren, editieren, Filtern, neu befüllen - was du wolle. Wird die Zelle gezeichnet, erhält sie, ihren Daten entsprechend die richtige Colorierung.
    Im ersten meiner Bildchen siehst du einen vergleichbaren Effekt da, wo in einer Zelle ein negativer Betrag zustande kommt - da verwende ich Rot als ForeColor.
    Oder die blaue BackColor hebt Personen-Konten von allgemeinen Geld-Töpfen (wie KleiderGeld) ab.

    Lightsource schrieb:

    @raist10:
    Ich verstehe was du meinst, aber ich frage mich dann wie der Compiler so etwas handhabt.
    Werden auf diese Weise nicht zusätzliche Daten und Rücksprungadressen auf den PC_Stack gelegt?
    Natürlich glaube ich, dass das Ganze übersichtlicher und wartbarer wird.


    Natürlich wird durch OOP (denn genau das ist es was ich Dir vorgeschlagen haben) mehr Stack-Platz verbraucht. Aber wir sind nicht mehr im Zeitalter von 64 kb RAM und selbst zeitkritische Anwendungen wie Games arbeiten sehr stark mit OOP. Und Du darfst auch nicht vergessen das die NET-Umgebung speziell für OOP geschaffen wurde und daher genau diese Art der Programmierung effektiver unterstützt als die alten Methoden.

    Stell Dir einen größeren Funktionsablauf vor, innerhalb dessen Du in einem prozeduralen Code-Aufbau zweimal die Connection zur DB öffnest ... das verbraucht viel mehr Zeit und Ressource als wenn Du 30 Objekte instanzierst und aber nur einmal die Connection-Klasse (Handler auf Objekte kannst Du ja problemlos durchreichen oder als Eigenschaft in der startenden Klasse zur weiteren Verwendung zur Verfügung stellen).

    In diesem Sinne ist der objektorientierte Ansatz i.d.R. perfomanter und ressourcenschonender als der prozedurale Aufbau. Vorallem weil jedes Objekt (Klasse) in sich selbst saubere Aufräumroutinen beinhaltet, entweder automatisch durch den GC oder selbst erstellte durch Implementierung der IDisposable-Schnittstelle. Deswegen schleppst Du bei sauberem objektorientierem Programmablauf (Objekt wird erst erzeugt wenn Bedarf ist und nach Verwendung auch wieder freigegeben) i.d.R. wesentlich weniger Müll/Schrott während der Programmausführung mit rum als bei prozeduralem Ablauf.

    Soll Dein Projekt größer werden kommst Du eh nicht um OOP herum. Ich kann Dir nur dringend empfehlen Dich damit auseinander zu setzen und schnellstmöglich darauf umzuschwenken. Es erspart Dir im Nachgang immens viel Arbeit, Nerven und vor allem Zeit ... zumindest ist es mir so ergangen als der Groschen fiel und ich auf OOP umgeschwenkt habe. ^^


    Ich habe mehrere Produkte, die ich durch verschiedene Hintergrungfarben der Zeilen
    klarer dargestellt haben will. Ich lese also die Spalte, in der die Produktnummer steht
    und schaue in einer entsprechenden Tabelle, in der der Farbkode steht (per SQL)
    daraufhin ändere ich die Hintergrundfarbe der betroffenen Zeile.


    Schlag Dir die Idee aus dem Kopf. ErfinderDesRades hat völlig Recht, Du schiebst ein riesen Rad vor Dir her nur um ein wenig mit Farbklecksen zu arbeiten.

    Überleg Dir ein Farbschema das ohne Datenbank-Zugriff aus kommt, sprich Du kannst die Farbgestaltung an Hand der Inhalte der Zellen feststellen. Die Farbcodes als Constante und die Regeln (Methoden) für die Anwendung kannst Du ja sauber in einer eigenen Klasse als Object programmieren und dann beim befüllen/neuzeichen/neu sortieren/verschieben etc. einfach durch die Klasse laufen lassen und jut ist. ;)

    Aber generell halt ich Farbspiele in DataGrids eh nicht für so irre sinnvoll. Man erreicht meistens das Gegenteil von dem was man will ... der User ist so mit Farben erschlagen das er ausser Farben nichts mehr sieht. ;)

    Meistens reichen einfache Sachen aus, wie z.B. Background-Color für Zeilen mit gerade Ziffer weiss und für Zeilen mit ungerader Ziffer hellgrau oder eine andere dezente Farbe und dann noch vielleicht negative Zahlen in rot.

    Da ich selber nur das sevDataGrid als DataGrid verwende kann ich Dir auch jetzt nicht genau sagen wie Du das mit dem von Dir verwendeten Grid umsetzen kannst.

    Gruß

    Rainer

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „raist10“ ()