Performance einer .NET Anwendung erhöhen (an welchen Parameter drehe ich)

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von dive26.

    Performance einer .NET Anwendung erhöhen (an welchen Parameter drehe ich)

    Hallo Leute,

    ich bin garade an meinem mittlerweile sechsten 1-Jahres Projekt dran und meine Aufgabe ist es meine alte ERP-Software (noch VB6) von Grund auf neu zu schreiben und mit neuen Funktionen und neuer Oberfläche auszustatten. Da die neue Anwendung Datenkompatibel zur alten bleiben soll, werden viele Programmteile (abgewandelt) weiterverwendet.

    Performance:
    Von VB6 Programmen kenne ich es, dass auch bei Vorhandensein von Multi-Core-Prozessoren nur immer ein einziger Kern verwendet wird.
    Bei .NET werden ja mitunter mehrere Kerne schon alleine durch die .NET Komponenten selbst verwendet. Also generell wird die Software schon etwas schneller laufen.

    * Wie kann ich die insgesamte Performance von .NET Programmen noch weiter erhöhen ohne echtes Multithreading zu programmieren?
    * Bringt es Geschwindigkeitsvorteile, wenn ich bei der Zielplattform statt x86 x64 verwende (die Anwendung wird nie über 800 MB im Speicher benötigen)?
    * Kann man an den Kompilierungs- Debug oder anderen Parametern in der IDE die Geschwindigkeit des Endproduktes mit ein paar Klicks erhöhen?
    * Welches ist die schnellste Anzeigevariante von Tabellenelementen welche ich manuell befülle und nicht direkt aus einer Datenbank heraus?
    Aktuell verwende ich Listviews, die werden aber langsamer je größer diese werden.

    Hintergrundinfo:
    Es geht nicht darum rechenintensive Aufgaben zu lösen (da wäre Multithreading interessant).
    Es geht um einen Mix an Programmfunktionen. Datenbank auslesen, Werte anzeigen, Fenster öffnen, schließen etc..
    Also eine Standard-Destktop-Anwendung.
    Bilder
    • 05092018121837.jpg

      268,38 kB, 917×828, 277 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Hallo

    Aus erfahrung weis ich (leider) das man die meiste Performance bei Datengetriebenen Anwendungen herausholen kann wenn man seine Datenbankabfragen wirklich mit bedacht schreibt.
    Bedeutet. Will ich alle Kunden in einem DateGrid darstellen ist es zum einen sehr schlecht alle zu laden. Entweder man verwendet Paging, oder man läd beim Scrollen, Sortieren usw. nach.
    Weiters benötigt man so gut wie nie alle Spalten. Ich sehe oft Abfragen wie "SELECT * FROM Kunden WHERE .......". gaaanz schlecht.
    Warum ruft man alle Spalten ab wenn man diese gar nicht benötigt.

    Ich verbringe oft wirklich mehrere Stunden damit meine Abfragen pro View zu optimieren und da holt man wirklich SEHR viel raus.

    Weiters musst du dir gedanken machen was genau du in einen nebenThread auslagerst und was nicht. Oft ist es einfach nur die "gefühlte" Performance.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Haha @Akanel. Stimmt!!

    Hab mir den Screenshot gar nicht angesehen. Gut gesehen :thumbup:
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    dive26 schrieb:

    Also generell wird die Software schon etwas schneller laufen.
    Das ist nicht gesichert.
    Du musst Dich darum kümmern, parallelisierbare oder asynchronisierbare Teile zu identifizieren und dann entsprechend zu implementieren.
    Für parallelisierbare Prozesse verwendest Du Parallel.For(...) oder Parallel.ForEach(...),
    asynchronisierbare Prozesse lässt Du mit Task.Run(...) laufen.
    Das eigentliche Problem dürfte sein, dass Du diese Prozesse identifizieren musst, und eine ERP-Software hat ja ein paar Zeilen Code mehr.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Du musst Dich darum kümmern, parallelisierbare oder asynchronisierbare
    Teile zu identifizieren und dann entsprechend zu implementieren.

    Für parallelisierbare Prozesse verwendest Du Parallel.For(...) oder Parallel.ForEach(...),

    asynchronisierbare Prozesse lässt Du mit Task.Run(...) laufen.

    Das eigentliche Problem dürfte sein, dass Du diese Prozesse
    identifizieren musst, und eine ERP-Software hat ja ein paar Zeilen Code
    mehr.


    Das mit der Parallelverarbeitung möchte ich mir generell ersparen - ist mir zu viel Aufwand. Es gibt auch keine Programmabläufe die hohe Rechenleistung und längere Berechnungsabläufe benötigen.

    Beispiel aktuelle Performance beim Abrufen von 10.000 Aufträgen und deren Anzeige:
    1. Lesen von 10.000 Datensätzen aus der Datenbank die auf einem freigegebenen Ordner auf einem anderen Rechner liegt
    2. Befüllen einer Listview (alle 10.000 Einträge)
    3. Anzeigen der Listview
    Diese Programmabfolge dauert vom Klick auf "Suchen" bis zur vollständigen Anzeige der Liste auf einem Core i5 Rechner mit SSD genau 3,3 Sekunden. Bei 1000 Aufträgen benötigen immerhin noch 0,35 Sekunden. Optisch sind sogar die 0,35 Sekunden zuviel. Die meiste Zeit nimmt der Punkt 2 in Anspruch.

    Wäre es möglich nur die ersten 100 Einträge im Listview zu befüllen, dies dem User dann anzuzeigen und dann im Hintergrund die anderen 9900 Einträge in die Listview hinzuzufügen (ohne Flackern und ohne Beeinträchtigung der Listview-Funktion? Bis der User dazu kommt runter oder rauf zu scrollen, sind die Daten ja eh schon alle da.

    Wichtig ist (wie @Nofear23m schon geschrieben hat), dass es für den User optisch flüssig geht.
    Bilder
    • Unbenannt-1.jpg

      538,63 kB, 1.362×745, 296 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „dive26“ ()

    Nimm mal bitte die Farbe Rot raus, die ist den Moderatoren vorbehalten.

    dive26 schrieb:

    ist mir zu viel Aufwand
    Das ist ganz easy.
    Das mit dem Nachladen von Datensätzen geht.
    Ich hab mal ein virtuelles ListView in Aktion gesehen, allerdings hab ich da keine Quellen, da musst Du mal selbst recherchieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Für WPF habe ich mir mal so ein DataGridView gebaut.

    Mach dir ein DataGridView welchem du eine x beliebige Abfrage übergeben kannst. Das GridView soll sich dann um den Rest kümmern so das es nur x Datensätze abrufe und im Hintergrund nachläd. Aber nur wenn überhaupt notwendig.
    Ich hab das damals so gemacht das im Footer angezeigt wird. 50 von 3026 Datensätzen geladen. Und bei Scrollen werden immer 50 oder 100 oder wie gewünscht nachgeladen. Ausser der User sortiert oddr sucht. Dann kommt ein Ladebalken und es werden in iner Schleife immer x Datensätze nachgeladen bis alles da ist oder der User evtl. abbrechen klickt.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Das GridView soll sich dann um den Rest kümmern so das es nur x Datensätze abrufe und im Hintergrund nachläd. Aber nur wenn überhaupt notwendig.


    Das mit dem DataGridView verwende ich bei 1:1 Datenbankauszügen. Aber für die Anzeige der Auftragsliste ist diese völlig ungeeignet weil ich da auch Farben, Icons und unterschiedliche Schriftarten verwende (siehe Screenshot vom letzten Beitrag).
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Sorry, da kann ich dir nicht helfen. Unter WPF ist das alles kein Problem unter WinForms weis ich es leider nicht.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Vielen Dank @ErfinderDesRades.

    Ich habe einige Vergleichstests mit dem Listview unter .NET und VB6 durchgeführt. Das Listview in .NET ist etwas schneller. Und mit ein paar optischen Tricks (im Hintergrund nachladen, Paging) klappt es dann auch. Listview ist für meine Bedürfnisse einfacher und individueller zu handhaben.

    Habe im Konzept schon einen automatischen Performance-Monitor der je nach Rechnergeschwindigkeit mehr oder weniger Elemente im Listview anzeigt. Dieser soll selbstlernend sein. Somit erreiche ich für den Endanwender eine "gefühlt" rasche Anzeige.

    Bin schon dabei die Oberfläche zu generieren - ohne WPF, da ich mit WPF leider nichts anfangen kann und umlernen möchte ich auch nicht ;)
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Ich habe jetzt einiges an Performance durch "korrekte" Programmierung herausholen können.
    Die alte ERP-Software war noch in VB6 und stümperhaft von mir programmiert worden. Das merke ich jetzt, da ich einige Funktionen aus VB6 stark verändert übernehme. Aber immerhin ist die alte ERP Software schon über 10 Jahre alt und ich habe inzwischen (auch mit Eurer Hilfe) viel dazugelernt.

    Da ich die Verwendung von Listviews der Einfachheit halber bevorzuge, habe ich mich damit etwas beschäftigt und etwas mehr an Performance herausgeholt.


    Seit ich BeginUpdate und EndUpdate verwende, geht das Befüllen um den Faktor 3 schneller.
    Wusste bisher gar nicht dass es diese Befehle gibt ;)

    VB.NET-Quellcode

    1. ListView.BeginUpdate()
    2. ' Listview befüllen
    3. ListView.EndUpdate()


    Bei den Datenbankabfragen wird nicht mehr SELECT * FROM sondern SELECT a,b,c FROM verwendet, was bei umfangreicheren Abfragen mit vielen Datensätzen einen leichten, aber messbaren Performancegewinn bringt.

    Die Verwendung von ProgressBar trägt zum "optischen" Performancegewinn bei - überall dort wo es einfach nicht schneller geht.

    Panels ein- und ausblenden geht ebenfalls schneller als wegen jeder Funktion ein separates Fenster zu öffnen.
    Bilder
    • boniterp2.jpg

      321,29 kB, 1.000×686, 191 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    Wusste bisher gar nicht dass es diese Befehle gibt
    Es ist sinnvoll, sich mal den Designercode anzusehen, der vom Studio erzeugt wird, wenn Du Deine GUI bearbeitest.
    Der steht in der Datei FormX.Designer.vb in der Prozedur InitializeComponents().
    Da lässt sich einiges abgucken...
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ein DataGridView anstatt einer ListView zu verwenden, erhöht die Performance auch nochmal ungemein.
    Spontan fällt mir noch ein, alle nicht benötigten Verweise zu entfernen, das bringt auch ein bischen was.
    Bei den Datenbankabfragen wird nicht mehr SELECT * FROM sondern SELECT a,b,c FROM verwendet, was bei umfangreicheren Abfragen mit vielen Datensätzen einen leichten, aber messbaren Performancegewinn bringt.


    Ich musste bei umfangreichen Datenbankabfragen aber das Gegenteil feststellen.

    Um zu sehen welche Abfrage- und Optionsänderungen die Performance beeinträchtigen, lasse ich jede meiner Datenbankabfragen 100x hintereinander durchlaufen und messe die Zeit.
    Wenn ich statt SELECT * FROM SELECT a,b,c FROM verwende, dann nimmt die Geschwindigkeit leicht ab.
    Bei mehr als 3 Feldnamen (statt dem *) wird die Abfrage langsamer als mit *. Egal ob nur eine Tabelle oder eine verknüpfte Tabellenabfrage.

    VB.NET-Quellcode

    1. "OLE DB Services=-1"
    im ConnectionString erhöht die Zugriffsgeschwindigkeit um ein paar Prozent.

    Schlussendlich führe ich nun bei allen Datenbankabfragen und bei allen anderen rechenintensiven Operationen einfach eine Mehrfachschleife mit Zeitmessung durch und verwende dann die schnellste (und natürlich auch sicherste) Methode.

    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    Also anstelle auf x86 oder x64 zu stellen würde ich dir AnyCpu empfehlen und dabei Prefer 32 bit abzustellen. Damit führt er auf ein 32bit system in 32 bit modus aus und auf einem 64 bit system im 64 bit modus.

    Damit haste solange du keine nativen libraries ohne COM verwedest die Kompatibilität mit beiden Systemen und bekommst bei 64bit dessen Vorteile.
    Also ja in der Theorie ist 64bit schneller, da dieses die x86 Befehlssätze alle enthält aber auch noch einige zusätzliche, welche z.b. Was zu vor mit zwei befehlen passierte in einem gemacht werden kann und die .Net runtime kann dies nutzen um mehr Performance raus zu holen. Doch für die meisten Fälle bringt es nicht sonderlich viel (ändert sich ggf jedoch mit verbesserung der runtime). Aber wie gesagt AnyCpu bringt sonst wenige Nachteile.

    Auch das winforms listview bietet anscheinend tatsächlich Virtualisierung an:
    docs.microsoft.com/en-us/dotne…e?view=netframework-4.7.2
    Natürlich müsstest du das anfordern von items hier bei cache miss anpassen und aus der Datenbank laden. Aber Achtung dabei solltest du am besten gleich einen ganzen chunk von daten in den cache laden, sonst wir die Performance schrecklich.
    Später dann wäre evtl sogar das memorypooling des caches eine Überlegung wert. Aber darum würde ich mich erst kümmern, wenn die eigt Virtualisierung funktioniert
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Also anstelle auf x86 oder x64 zu stellen würde ich dir AnyCpu empfehlen und dabei Prefer 32 bit abzustellen. Damit führt er auf ein 32bit system in 32 bit modus aus und auf einem 64 bit system im 64 bit modus.


    Leider habe ich eine unverzichtbare externe Komponente, welche unte 64 Bit nicht ordentlich funktioniert. Daher muss ich gezwungenermaßen bei 32 Bit bleiben. Mir wäre 64 Bit auch lieber.
    Edit: Das Problem habe ich schon gelöst - läuft auf AnyCPU.

    Wirklich rechenintensive Operationen habe ich ja keine in der Software. Die zeitkritischsten Systeme sind der Datenbankaufruf und die Bildschirmausgabe von großen Datenmengen.

    Die Virtualisierung, wie von Dir angesprochen, habe ich auch schon versucht. Aber um hier einen wirklichen Performancegewinn zu erzielen, habe ich zu wenig Daten auszugeben. Da ist es schneller alles in den Speicher zu laden als häppchenweise von der Datenbank abzurufen. RAM Speicher gibt es ja genug in den aktuellen Systemen - und warum dann nicht auch ausnutzen.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    Naja das ziel wäre ja, dass der nutzer lieber 100 mal 50 ms wartet als 1 mal 3s. Abgesehen davon, dass man selbst das in vielen Fällen verhindern kann. Wenn man davon ausgeht, dass der benutzer eher nicht zufällig hin und her springt sondern seite für seite geht. Dann kann man bereits bevor gescrollt wird im Hintergrund mehr laden. Dann merkt der benutzer gar keine Verzögerung.

    Und um welche 32 bit Komponenten handelt es sich denn? Vlt. Kann man da auch was schrauben.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Danke für Deine Inputs.

    "Seitenweises Blättern" durch Datensätze ist in meiner Anwendung in keinem Punkt eine brauchbare Option, da vom Ablauf hier nicht zielführend. Man braucht entweder alle Daten auf einen Blick (mit Summenbildung) und schränkt auf einzelne Jahre oder andere Sortierkriterien ein (z.b. Volltextsuche).

    Jede Einzelne Datenbankabfrage (egal ob ein 1 oder 1000 Datensätze) braucht schon eine "Grundzeit" für die Abfrage. Daher sind die 50ms pro Datenbankabfrage zwar rechnerisch weniger, aber durch die immer wieder benötigte "Grundabfragezeit" am Bildschirm gefühlt wesentlich länger. Für meine Anwendung also derzeit keine Option.

    Für meine Anwendung habe ich schon die optimalen Einstellungen gefunden und meine neuen Abfragen und Auflsitungen sind schon mal 50% schneller als die meiner alten Anwendung (die war noch VB6). Diese Routinen sind schon fertiggestellt und hier bedarf es auch keiner Änderung mehr.

    Meine Anwendung läuft eh schon auf AnyCPU (x86 prefered). Das funktioniert schon - das Problem habe ich schon gelöst.

    Dennoch vielen Dank für Deine Hilfe und Anregungen.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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