Unterschied StringBuilder.Append und Neuzuweisung

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

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

    Unterschied StringBuilder.Append und Neuzuweisung

    Hallo,

    wo ist der Unterschied wenn ich in der Stringbuilder-Klasse operiere anstatt in der String Klasse? Beispiel:

    VB.NET-Quellcode

    1. Dim Strbuild as New StringBuilder("abc",6)
    2. Strbuild.Append("def")
    3. '----------
    4. Dim str As String = "abc"
    5. str = str & "def"


    Viele Grüße
    Der StringBuilder ist deutlich (!) schneller beim verketten großer Texte.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @Haudruferzappeltnoch Der StringBuilder ist für das Verketten von Strings gemacht.
    Das Resultat beider Operationen bei Dir ist dasselbe, und den Geschwindigkeitsvorteil bekommst Du, wenn das oft genug aufgerufen wird.
    In Deinem Fall würde ich die String-Variante nehmen.
    Bei mehr als sagen wir 5 Verkettungen nehme ich einen StringBuilder, das hängt natürlich auch vom Kontext ab.
    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!
    @Haudruferzappeltnoch Der ist genau dafür gemacht.
    Strings können nicht in sich editiert werden, die erzeugen eine neue String-Instanz.
    Der StringBuilder arbeitet auf einem (hinreichend) großen Speicher, und wenn der nicht reicht, vergrößert er ihn.
    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!
    Hab das neulich bei mir getestet mit einer Consolenanwendung:

    5000 mal einen Text (je ca. 900 Zeichen) verketten:

    StringBuilder: 0,0080853 Sekunden
    String.Concat: 9,2904944 Sekunden
    "Normal": 9,4564312 Sekunden
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Kannst du den Code zeigen?
    Es gibt noch weitere Möglichkeiten, Strings performant zu verketten.
    Und es gibt ja auch unterschiedliche Problemstellungen.
    Probleme gibts ja meist nur, wenn an denselben String immer mehr und mehr Strings angehängt werden sollen.
    Grade da kann man mit einer List(Of STring), und dann String.Concat(myStringList) ähnlich hervorragende Werte erzielen wie mit StringBuilder.

    ErfinderDesRades schrieb:

    an denselben String immer mehr und mehr Strings angehängt werden
    Ja genau das macht mein Code in dem Beispiel. Kann ich gerne morgen posten falls noch interessiert.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Danke euch.
    PS:
    Hierfür benutze ich es momentan ("abc" ist nicht unbedingt dasselbe)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim Druck as StringBuilder
    2. Druck.Append("abc")
    3. Druck.Append("abc")
    4. Druck.Append(arrDruckdaten(7))
    5. Druck.Append("abc")
    6. Druck.Append(arrDruckdaten(4))
    7. Druck.Append("abc")
    8. If arrDruckdaten(2).Length > 16 Then
    9. Druck.Append(arrDruckdaten(2).Substring(0, 16))
    10. Else
    11. Druck.Append(arrDruckdaten(2))
    12. End If
    13. Druck.Append("abc")
    14. If arrDruckdaten(3).Length > 16 Then
    15. Druck.Append(arrDruckdaten(3).Substring(0, 16))
    16. Else
    17. Druck.Append(arrDruckdaten(3))
    18. End If
    19. Druck.Append("abc")
    20. Druck.Append(arrDruckdaten(6))
    21. Druck.Append("abc")
    22. Druck.Append(arrDruckdaten(5))
    23. Druck.Append("abc")
    24. Druck.Append(arrDruckdaten(1))
    25. Druck.Append("abc")
    26. Druck.Append(arrDruckdaten(0))
    27. Druck.Append("abc")
    28. Druck.Replace("ß", "ss")
    29. Druck.Replace("ä", "ae")
    30. Druck.Replace("ö", "oe")
    31. Druck.Replace("ü", "ue")
    32. Druck.Replace(" 00:00:00", "")
    33. Druck.Replace("-", "")

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

    ErfinderDesRades schrieb:

    Kannst du den Code zeigen?

    Hier der Testcode.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Rows As Integer = 5000
    2. Sub Main()
    3. Console.WriteLine($"{Rows.ToString} Texte verketten:")
    4. WriteText()
    5. Console.ReadLine()
    6. End Sub
    7. Private Sub WriteText()
    8. AddString()
    9. BuildString()
    10. ConcatString()
    11. End Sub
    12. Private Sub AddString()
    13. Dim txt As String = ""
    14. Dim sw As New Stopwatch
    15. sw.Start()
    16. For i As Integer = 0 To Rows
    17. txt &= GetValues() & vbCrLf
    18. Next
    19. sw.Stop()
    20. Console.WriteLine("Normal: " & sw.Elapsed.TotalSeconds)
    21. End Sub
    22. Private Sub BuildString()
    23. Dim sb As New StringBuilder()
    24. Dim sw As New Stopwatch
    25. sw.Start()
    26. For i As Integer = 0 To Rows
    27. sb.Append(GetValues() & vbCrLf)
    28. Next
    29. sw.Stop()
    30. Console.WriteLine("StringBuilder:" & sw.Elapsed.TotalSeconds)
    31. End Sub
    32. Private Sub ConcatString()
    33. Dim txt As String = ""
    34. Dim sw As New Stopwatch
    35. sw.Start()
    36. For i As Integer = 0 To Rows
    37. txt = String.Concat(txt, GetValues() & vbCrLf)
    38. Next
    39. sw.Stop()
    40. Console.WriteLine("ConcatString: " & sw.Elapsed.TotalSeconds)
    41. End Sub
    42. Private Function GetValues() As String
    43. Return "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem"
    44. End Function


    In meinem Hauptprojekt hat der Wechsel vom "normalen" String verketten (str &= "foo") zum StringBuilder eine Zeitersparnis von ~60 Sekunden gebracht. Der Code oben entsprich in etwa dem, was ich dort gemacht habe.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @Haudruferzappeltnoch Das sieht doch ganz gut aus. Hast Du da fortlaufenden Text ohne Zeilenschaltung?
    Vielleicht nur als Erinnerung:
    StringBuilder.Append(...) schreibt den Text unmittelbar hinter einander,
    StringBuilder.AppendLine(...) hängt eine neue Zeile an den bestehenden Text,
    StringBuilder.AppendLine() hängt eine Leerzeile an den bestehenden Text.
    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!

    mrMo schrieb:

    Hier der Testcode.
    Tja, sieht so aus, dass StringList.Add() fast doppelt schneller ist als StringBuilder.Append:

    VB.NET-Quellcode

    1. Private Sub WriteText()
    2. StringList()
    3. BuildString()
    4. End Sub
    5. Private Sub StringList()
    6. Dim sw = Stopwatch.StartNew
    7. Dim stringList = New List(Of String)
    8. For i As Integer = 0 To Rows
    9. stringList.Add(GetValues())
    10. Next
    11. Dim txt = String.Join(vbCrLf, stringList)
    12. Debug.WriteLine("StringList: " & sw.Elapsed.TotalSeconds)
    13. End Sub
    14. Private Sub BuildString()
    15. Dim sw = Stopwatch.StartNew
    16. Dim sb As New StringBuilder()
    17. For i As Integer = 0 To Rows
    18. sb.Append(GetValues() & vbCrLf)
    19. Next
    20. Dim txt = sb.ToString
    21. Debug.WriteLine("StringBuilder:" & sw.Elapsed.TotalSeconds)
    22. End Sub

    Ausgabe:

    Quellcode

    1. 5000 Texte verketten:
    2. StringList: 0,0264019
    3. StringBuilder:0,0455086
    Aber das ist beides so schnell, dass es
    1. egal ist
    2. Windows-ThreadOptimierung stark ins Ergebnis hineinspielt
      Also je häufiger eine Methode aufgerufen wird, desto schneller wird sie.
      Und der erste Benchmark ist immer merklich langsamer als folgende

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Es gibt diverse Artikel dazu, dieser hier ist auch interessant und führt deine Erläuterung weiter aus. Ein Artikel aus der Knowledgabse ist ebenfalls verlinkt.
    Hier noch ein Benchmark, und noch einer. ein Thema das viele umtrieben hat.
    Ein sehr interessanter Artikel ist auch der hier, der u.a. auch Stringbuilder behandelt.
    Nicht davon beirren lassen, dass die Artikel meist von C# schreiben, es geht eh ums Framework, und das ist das selbe.
    Hmm - wirklich nützlich?
    Weil Du hast doch jetzt schon zwei höchst performante Vorgehensweisen - das ist doch mehr als du brauchst.
    Das einzige, was man sich merken muss, ist dass man nicht hunderte Male am selben String noch was hinten ranhängen sollte - vor allem nicht, wenn der String recht lang ist.
    Weil Hinten dranhängen ist jedesmal ein Neu-Alloziieren von Speicher und dann Umkopieren.
    Vermeiden kann man das mittm StringBuilder oder ich finde noch einfacher und mächtiger, mit einer List(Of String) - wo man den String nicht sukzessive zusammenbaut, sondern die Stückchen Stückchen sein lässt, bis alles fertig, und am Ende mit einem Befehl (String.Join oder String.Concat) verketten.