Performance von Variablen Zuweisung und Deklaration

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

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

    Performance von Variablen Zuweisung und Deklaration

    Hallo,

    ich habe eine Methode in der eine ganze Reihe von Variablen deklariert und zugewiesen werden:

    VB.NET-Quellcode

    1. Sub Pseudo
    2. Dim a = 1
    3. Dim b = "x"
    4. ...
    5. End Sub


    Die Methode wird jedoch mehrfach aufgerufen. Jetzt frage ich mich, ob es sich lohnt die Variablen außerhalb (also als Klassenvariablen) zu deklarieren und in der Methode nur noch die Zuweisungen vorzunehmen, denn daduch spare ich ja theoretisch das Aufräumen und jede weitere Deklaration pro Methodenaufruf. Also wie wirkt sich Aufräumen und Deklaration auf die Performance aus?

    Viele Grüße

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

    Haudruferzappeltnoch schrieb:

    Also wie wirkt sich Aufräumen und Deklaration auf die Performance aus?

    Ausprobieren?

    Haudruferzappeltnoch schrieb:

    ob es sich lohnt die Variablen außerhalb (also als Klassenvariablen) zu deklarieren

    Brauchst du sie außerhalb? Scheinbar nicht, sonst hättest du sie ja bereits außerhalb verfügbar...

    Wenn sich also bei deinem "Ausprobieren" herauskristallisiert, dass es keine Verbesserung bringt, wozu die Klasse vollmüllen wenn du die Variablen nur lokal in der Methode brauchst?
    Dumm ist der, der dumm ist. Nicht andersrum!
    Das Auslagern ist absolut Overkill. Variablen sollten so lokal wie möglich gehalten werden. Nur wenn eine Wertermittlung nachweislich/für den User bemerkbar (!) Perfornaceeinbußen mit sich bringt, dann ist zu überlegen, wie man dafür sorgt, dass die Wertermittlung nur sooft wie nötig durchgeführt wird. Aber bei den genannten Fällen schafft ein moderner PC Millionen von Deklarationen und Entsorgung der Variablen, während man einmal kurz hustet.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ok, die Methode wird in einer Schleife an die 200 mal aufgerufen und macht das mit ca. 70 Variablen. Das hält sich zeitlich gerade die Waage mit einem DBAbruf (~2sek), was ich schon ein bisschen viel finde,
    wenn die Deklaration davon 90% ausmacht würd ichs machen, bei <50% ist, lass ich sie lokal.

    Ausprobieren ist in dem Sinn ja schon etwas aufwendiger, da wollte ich zumindest mal vorher nachfragen wie groß der Deklarationsanteil an einer Zuweisung wohl sein mag oder könnt ihr das auch nicht abschätzen? Dann ists auch ok.

    Die Variablen brauch ich nur lokal in dieser Methode

    Haudruferzappeltnoch schrieb:

    Ausprobieren ist in dem Sinn ja schon etwas aufwendiger


    Wäre in den zwei Stunden jetzt machbar gewesen oder?

    Kannst doch einfach mal grob messen wie lange das aktuell in deiner Methode dauert, bis die lokalen Variablen einen Wert zugewiesen haben.
    Aber wie @VaporiZed bereits erwähnt hat, geht das alles ziemlich schnell vonstatten und sollte nicht dein Problem sein.
    Dumm ist der, der dumm ist. Nicht andersrum!
    @Haudruferzappeltnoch Mach Dir ggf. eine Datenklasse mit einer Init()-Prozedur, die kannst Du aufrufen, um einen Initialzustanz herzustellen.
    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!
    @Schmittmuthelm Hab garnicht gemerkt, dass ich in der Zeit zwischen den Posts schlafen gehe ^^ Wie gesagt, hätte ja sein können, dass ihr das aus dem Bauch raus wisst.

    @RodFromGermany Da kann ich nicht ganz folgen.
    Wie verhindere ich damit die mehrfach Deklaration? Die müsste ich dann auch auf Klassenebene anlegen oder? Bin mir aber nicht sicher was du meinst.

    Haudruferzappeltnoch schrieb:

    Die müsste ich dann auch auf Klassenebene anlegen oder?
    Ich sehe, Du hast es verstanden:

    VB.NET-Quellcode

    1. Class DataClass
    2. Public Value As Integer
    3. Public Sub Init()
    4. Value = 42
    5. End Sub
    6. End Class
    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!
    Ok Ich denke du meinst es dann so:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Class Form1
    2. Private DC as New DataClass
    3. Sub Pseudo
    4. DC.Init()
    5. ...
    6. End Sub
    7. End Class
    8. Class DataClass
    9. Public Value As Integer
    10. Public Sub Init()
    11. Value = 42
    12. End Sub
    13. End Class


    In Zusammenhang mit den obigen Aussagen, heißt das, ich verlagere das sogenannte "vollmüllen" in eine andere Klasse?
    Das ist richtig. Das führt dazu, dass Du die ganze Schreibarbeit quasi in einer anderen Datei hast und Deine Form-Klasse schlank halten kannst. Allerdings frag ich mich, was das werden soll, wenn ich lese: in einer Methode 70 Variablen. Was ist das für ein Konstrukt, das solche Datenmengen allein braucht? Ich will die Notwendigkeit nicht in Abrede stellen, aber ich vermute, dass bei 70 benötigten Variablen Optimierungsbedarf besteht. Kannst Du da mal einen Beispielpseudocode zeigen, der die Notwendigkeit von 70 Variablen bei 200 Aufrufen verdeutlicht?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @VaporiZed Jou.
    @Haudruferzappeltnoch Richtig umgesetzt.
    Eine solche Datenklasse kannst Du außerdem sehr bequem abspeichern (=> Serialisierung, xml oder bin).
    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!
    @Dksksm für den Fall, dass ASP.NET verwendet wird.
    Sinnigerweise werden da keine Alternativen aufgezeigt. ;(
    ====
    Der Witz dabei besteht darin, dass bei binärer Serialisierung der komplette Speicherinhalt der Klasseninstanz auf dere Platte abgelegt wird.
    Die Methoden sind dabei so genial, dass ein Upgrade quasi online möglich ist.
    Schade, dass das raus soll.
    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!
    JA das steht da, aber mach mal ein normales Winform Projekt mit Core5, da bekommst einen dicken Hinweis, dass das nicht mehr unterstützt wird.
    Alternativen sind JSON, wo MS ja auch mittlerweile ein eigenes Werkzeug hat, dass man für Net.Framework per NuGet einbinden kann und bei Core5 oder 6 (bin jetzt nicht ganz sicher) nativ eingebaut ist.
    Zweite Alternative ist XML-Serialisierung, würde ich nicht als Alternaive sehen, aber nun ja...
    @Dksksm XML-Serialisiere mal eine Klasse, die eine Variable vom Typ IPAddress hat.
    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!
    Da besteht definitiv Optimierungsbedarf, Code bring ich morgen.
    Vorderst wird ein Datensatz abgerufen. Aus dem Datensatz brauch ich fast alle Infos, die brauche ich aber auch in Abhängigkeit zueinander. Das heißt ich muss innerhalb des Datensatzes auch ne gewisse Logik abfragen um zu bestimmen, was ich denn am Ende haben will. Die Logik selbst ist sehr spezifisch, da lässt sich nix pauschalisieren

    Ja n Beispielcode ist gar nicht mal so einfach, ich muss wohl ans Original dran (kann ich leider jetz erstmal nicht) um zu zeigen was da passiert.

    In etwa gehts so los:

    VB.NET-Quellcode

    1. Dim datensatz = dt.Where(Function(x) x.col1 = f1 AndAlso x.col2 = f2 AndAlso x.col3 = f3).ToArray
    2. col1 = datensatz(0).col1
    3. col2 = datensatz(0).col2
    4. col3 = datensatz(0).col3
    5. col3 = datensatz(0).col4
    6. col3 = datensatz(0).col5
    7. ...


    Offensichtliche Schwachstellen sind zum Beispiel die Sachen, die gar nicht zugewiesen werden müssen. Das Ganze läuft ja in einer Schleife in der sich f2, f3 ändern, eine Variable ändert sich in der ganzen Schleife gar nicht col1, zwei weitere sind bekannt eben col2 und col3. Sich das zu sparen ist wahrscheinlich noch nicht der Bringer.
    Dann gibt es Werte, die in Abhängigkeit zueinander konstant in der Schleife sind, sprich wenn col20 in einer Datenzeile den gleichen Wert wie in einer anderen Datenzeile hat (genannt x), dann entspricht sich col21 auch in diesen Zeilen (genannt y). Allerdings lässt y sich nicht aus x ableiten und umgekehrt gilt das Ganze auch nicht zwingend. Diese Zuweisungen wären also rein logisch betrachtet in unbestimmten Schleifenschritten überflüssig, allerdings glaube ich nicht dass das umsetzbar ist, das so spezifisch rauszunehmen ohne trotzdem reinzugucken.
    Naja den Rest kann man wohl erst am Code sehen.

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Oh, da hast Du ja noch nachbearbeitet. Hm, bin dann irgendwie trotzdem nicht schlauer als vorher. Ist alles entweder zu allgemein gehalten oder das Problem ist zu spezifisch, um da noch was zu machen, ohne das Original im Ganzen und die Logik dahinter in voller Blüte zu erfassen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ich glaub, ihr bearbeitet grade eine andere Frage - wobei ich leider nicht weiss, welche.



    Hier diese Frage fand ich

    Haudruferzappeltnoch schrieb:

    vorher nachfragen wie groß der Deklarationsanteil an einer Zuweisung wohl sein mag oder könnt ihr das auch nicht abschätzen?
    Sicher bin ich nicht - müsste ich also auch ausprobieren.
    Da probier doch lieber du aus, und sags uns.
    Ich könnte mir vorstellen, der Mehr-Aufwand für viele Variablen ist nahe Null. Also falls sich Variablen-Deklarationen nur in der Speicher-Alloziierung der Methode wiederspiegeln. Diese Alloziierung findet eh statt, und ob er die Size nu auf 20 oder auf 2000 Bytes festlegt macht zeitlich keinen Unterschied - ist ja nur eine andere Zahl.
    Jetzt wollt ich grad ein ellenlanges Beispiel darbieten, da habe ich den Übeltäter gefunden. Ich hatte noch eine Abfrage in dem Bereich. Die hat die Zeit gefressen.
    Dann kann ich jetzt auch das bestätigen, was ihr mir sagtet.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Falls Bedingung:
    2. Private Sub Extrahiere(Prod As Integer)
    3. #Region "Auswahl des Produkts"
    4. Dim view = DS1.dtRecent.Where(Function(x) x.prodnr = Prod AndAlso x.snr = 1).ToArray
    5. #End Region
    6. #Region "Parameter auslesen und einstellen"
    7. Dim ProdNr = view(0).prodnr
    8. Dim Form = 1
    9. ...Dim mehrere variablen = view(0).mehrerevariablen...
    10. Dim KundNr = view(0)
    11. Dim Str = Substr(view(0).Str, 0, 33).Replace("'"c, "`"c)
    12. If view(0).KundeStr = "" Then
    13. KundeStr = " "
    14. End If
    15. Dim Ort = Substr(view(0).Ort, 0, 33)
    16. Dim K5 = Substr(view(0).K5, 0, 33)
    17. ...
    18. Dim UKNr = 0
    19. Dim UKStr = ""
    20. Dim UKOrt = ""
    21. If KundNr <> 0 Then
    22. UKNr = view(0).UKNr
    23. UKStr = Substr(view(0).UKStr, 0, 33).Replace("'"c, "`"c)
    24. UKOrt = Substr(view(0).UKOrt, 0, 33).Replace("'"c, "`"c)
    25. End If
    26. Dim LiefStr = Substr(view(0).LiefStr, 0, 33).Replace("'"c, "`"c)
    27. If UKNr > 0 Then
    28. LiefStr = UKStr
    29. ElseIf UKNr = 0 Then
    30. LiefStr = KundStr
    31. End If
    32. Dim Liefer1 = Substr(view(0).LieferAn2, 0, 33).Replace("'"c, "`"c)
    33. ...
    34. Dim KZ1 = view(0).KZ1
    35. Dim Bez = view(0).Bez
    36. Dim BasisBez1 = ""
    37. Dim BasisBez2 = ""
    38. Dim BasisBez3 = ""
    39. Dim Bereich As String()
    40. Dim SZahl As Integer
    41. If KZ1 > 0 Then
    42. Bereich = Bez.Split("@"c)
    43. SZahl = Bez.Split("@"c).Length - 1
    44. If SZahl = 2 Then
    45. BasisBez1 = Substr(Bereich(1), 0, 49)
    46. BasisBez2 = Substr(Bereich(2), 0, 49)
    47. End If
    48. If SZahl = 3 Then
    49. BasisBez1 = Substr(Bereich(1), 0, 49)
    50. BasisBez2 = Substr(Bereich(2), 0, 49)
    51. End If
    52. If SZahl = 4 AndAlso Bereich(2).Contains("Abstand") Then
    53. BasisBez1 = Substr(Bereich(1), 0, 49)
    54. BasisBez2 = Substr(Bereich(3), 0, 49)
    55. ElseIf SZahl = 4 AndAlso Not Bereich(2).Contains("Abstand") Then
    56. BasisBez1 = Substr(Bereich(1), 0, 49)
    57. BasisBez2 = Substr(Bereich(2), 0, 49)
    58. BasisBez3 = Substr(Bereich(3), 0, 49)
    59. End If
    60. If SZahl = 6 Then
    61. BasisBez1 = Substr(Bereich(1), 0, 49)
    62. BasisBez2 = Substr(Bereich(3), 0, 49)
    63. BasisBez3 = Substr(Bereich(5), 0, 49)
    64. End If
    65. If SZahl = 9 Then
    66. BasisBez1 = Substr(Bereich(1), 0, 49)
    67. BasisBez2 = Substr(Bereich(6), 0, 49)
    68. BasisBez3 = Substr(Bereich(8), 0, 49)
    69. End If
    70. If SZahl = 9 AndAlso Bereich(3).Contains("VB12") Then
    71. BasisBez1 = Substr(Bereich(1), 0, 49)
    72. BasisBez2 = Substr(Bereich(2), 0, 49)
    73. BasisBez3 = ""
    74. End If
    75. Artikel = Bereich(0)
    76. End If
    77. Dim bez_ext = view(0).bez_ext
    78. If KZ1 = 0 AndAlso bez_ext.Contains("@"c) Then
    79. Bereich = Bez.Split("@"c)
    80. If Bereich(0).Contains("aus") Then
    81. Artikel = Substr(Bereich(0), 0, Bereich(0).IndexOf("aus") - 2)
    82. Else
    83. Artikel = Bereich(0)
    84. End If
    85. End If
    86. 'Naja so gehts dann auch noch weiter, das Konzept bleibt ähnlich
    87. #End Region
    88. #Region "Code"
    89. 'Hier wird ein maschinenlesbarer Code gebastelt
    90. Dim sbEtiText As New StringBuilder
    91. sbEtiText.AppendLine($"abc{Variablen}")
    92. ...
    93. #End Region
    94. #Region "DB Füllen"
    95. Dim inssql = ""
    96. Using inscon As New SqlConnection(DBZ.SqlConn(0))
    97. inscon.Open()
    98. Using inscmd As New SqlCommand(inssql, inscon)
    99. inscmd.ExecuteNonQuery()
    100. End Using
    101. inscon.Close()
    102. End Using
    103. 'Dieser Teil ist noch gar nicht gut, ich lese in der "Auswahl" Region eine Datenzeile ein, die Datenzeile soll dann umgebaut in eine andere Tabelle.
    104. 'Für den Umbau brauche ich also den ganzen Prozess in der Mitte. Dann Inserte ich aber immer nur diese eine resultierende Datenzeile
    105. 'Hier denke ich wäre es vermutlich besser die resultierenden Datenzeilen erstmal nur ins DataSet aufzunehmen und außerhalb der Schleife
    106. 'dann die ganze Tabelle mit den neuen Datenzeilen aufeinmal in eine DB zu blasen, da das dann ja nur ein Zugriff ist.
    107. 'Nur weiß ich nicht ob sowas überhaupt geht
    108. #End Region
    109. DBZ = Nothing
    110. End Sub
    111. 'Dann gibts noch ein ansonsten:
    112. Pseudosub machts ganz ähnlich

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()