Frage An welchem ​​Punkt wird die Verwendung eines StringBuilders unbedeutend oder ein Overhead?


Vor kurzem habe ich mich mit StringBuilder für alle String-Verkettungen beschäftigt, groß und klein, aber in einem letzten Performance-Test tauschte ich einen Kollegen aus stringOut = string1 + "." Zeichenfolge2 Style-Verkettung (wird in einer 10000x + -Schleife verwendet, wobei der StringBuilder jedes Mal neu erstellt wird) für einen StringBuilder, nur um zu sehen, welchen Unterschied er in einer kleineren Verkettung machen würde.

Ich habe festgestellt, dass die Änderung bei vielen Durchläufen des Leistungstests unabhängig von der Verkettung oder dem StringBuilder sowohl geringfügig höher als auch niedriger war klein Verkettungen).

An welchem ​​Punkt negiert das "newing up" eines StringBuilder-Objekts die Vorteile eines StringBuilder-Objekts?


16
2018-02-15 10:55


Ursprung


Antworten:


Die Regel, der ich folge, ist -

Verwenden Sie einen StringBuilder, wenn die Anzahl der Verkettungen zur Kompilierzeit unbekannt ist.

In diesem Fall hat jeder StringBuilder nur einige Male angefügt und dann verworfen. Das ist nicht wirklich dasselbe wie etwas wie

string s = String.Empty;
for (int i = 0; i < 10000; ++i)
{
    s += "A";
}

Die Verwendung eines StringBuilders würde die Leistung drastisch verbessern, da Sie sonst ständig neuen Speicher zuweisen würden.


20
2018-02-15 11:01



Ich bin mir sicher, dass ich eine andere Antwort habe, wo ich nur eine geschrieben habe Link zu meinem Artikel und dann seine Zusammenfassung, aber hier gehen wir wieder.

  • Definitiv verwenden StringBuilder Wenn Sie in einer nicht-trivialen Schleife verketten - insbesondere wenn Sie nicht genau wissen (zur Kompilierzeit), wie viele Iterationen Sie durch die Schleife durchführen werden. Wenn Sie zum Beispiel eine Datei zu einem bestimmten Zeitpunkt lesen und dabei eine Zeichenkette mit dem Operator + = erstellen, ist dies möglicherweise ein Leistungsselbstmord.

  • Verwenden Sie den Verkettungsoperator unbedingt, wenn Sie (lesbar) alles angeben können, was in einer Anweisung verkettet werden muss. (Wenn Sie eine Reihe von Dingen verketten müssen, ziehen Sie in Erwägung, anzurufen String.Concat explizit - oder String.Join wenn Sie ein Trennzeichen benötigen.)

  • Haben Sie keine Angst, Literale in mehrere verkettete Bits zu zerlegen - das Ergebnis wird dasselbe sein. Sie können die Lesbarkeit verbessern, indem Sie beispielsweise ein langes Literal in mehrere Zeilen aufteilen, ohne die Leistung zu beeinträchtigen.

  • Wenn Sie die Zwischenergebnisse der Verkettung für etwas anderes als die nächste Iteration der Verkettung benötigen, StringBuilder wird dir nicht helfen. Wenn Sie zum Beispiel einen vollständigen Namen aus einem Vornamen und einem Nachnamen erstellen und dann am Ende eine dritte Information (den Spitznamen, vielleicht) hinzufügen, profitieren Sie nur davon StringBuilder wenn Sie die Zeichenfolge (Vorname + Nachname) für andere Zwecke nicht benötigen (wie im Beispiel, das eine Person Objekt).

  • Wenn Sie nur ein paar Verkettungen zu tun haben, und Sie wollen sie wirklich in separaten Anweisungen tun, ist es nicht wirklich wichtig, auf welche Art Sie gehen. Welcher Weg effizienter ist, hängt von der Anzahl der Verkettungen, der Größe der beteiligten Zeichenketten und der Reihenfolge ab, in der sie verkettet sind. Wenn Sie wirklich glauben, dass dieser Codeabschnitt ein Leistungsengpass ist, profilieren Sie ihn in beide Richtungen.


17
2018-02-15 13:19



Manchmal lohnt es sich, die Dokumentation:

Die Leistung einer Verkettung   Operation für einen String oder   StringBuilder-Objekt hängt davon ab, wie   oft tritt eine Speicherzuordnung auf. EIN   String Verkettung Operation immer   reserviert Speicher, während a   StringBuilder-Verkettungsoperation   reserviert nur Speicher, wenn der   StringBuilder Objektpuffer ist auch   klein, um die neuen Daten aufzunehmen.   Folglich ist die String-Klasse   vorzuziehen für eine Verkettung   Operation wenn eine feste Anzahl von String   Objekte werden verkettet. In diesem   Fall, die individuelle Verkettung   Operationen könnten sogar kombiniert werden   eine einzelne Operation vom Compiler. EIN   StringBuilder Objekt ist vorzuziehen für   eine Verkettungsoperation wenn ein   Beliebige Anzahl von Strings sind   verkettet; zum Beispiel, wenn eine Schleife   verkettet eine zufällige Anzahl von   Strings der Benutzereingabe.

In Ihrem Beispiel gibt es nur eine einzige Verkettung pro Ausgabezeichenfolge, daher erhält StringBuilder nichts. Sie sollten StringBuilder in Fällen verwenden, in denen Sie zu dem hinzufügen gleiche Zeichenfolge oft, z.B .:

stringOut = ...
for(...)
    stringOut += "."
    stringOut += string2

6
2018-02-15 11:10



Meine Faustregel ist einfach.

  1. Wenn Sie vernünftigerweise einen einzelnen Ausdruck schreiben können, der das Finale erzeugt, dann verwenden Sie +.
  2. Wenn dies nicht möglich ist (entweder aufgrund der Größe oder der Variabilität), verwenden Sie StringBuilder.

Meiner Erfahrung nach, Ausdrücke wie:

"Id: " + item.id + " name: " + item.name

kann viel einfacher geschrieben und verstanden werden als:

StringBuilder sb = new StringBuilder();
sb.append("Id: ").append(item.id);
sb.append(" name: ").append(item.name);

(gefolgt von der Verwendung der Zeichenfolge aus sb wo der obige Ausdruck geschrieben worden wäre, und es funktioniert genauso gut (Hinweis: schau dir den kompilierten Code an, um zu sehen, warum!)

Auf der anderen Seite, wenn es notwendig ist, eine Zeichenfolge im Laufe der Zeit (während das Programm läuft) oder Leerzeichen (bestehend aus Werten, die von verschiedenen Teilen des Codes kommen) zu akkumulieren, auf eine Weise, die unpraktisch ist, als ein einzeiliger Ausdruck zu schreiben , dann vermeidet StringBuilder den Overhead (Zeit und Memory-Churning) von:

String s = somethingExpression;
...
s += someOtherExpression;
...
s += yetAnotherExpression;
...

2
2018-02-15 13:22



Von MSDN:

[T] er String-Klasse ist für a vorzuziehen   Verkettungsoperation wenn eine feste   Anzahl der String Objekte sind   verkettet. In diesem Fall   einzelne Verkettungsoperationen   könnte sogar zu einem einzigen kombiniert werden   Operation vom Compiler. EIN   StringBuilder Objekt ist vorzuziehen für   eine Verkettungsoperation wenn ein   Beliebige Anzahl von Strings sind   verkettet; zum Beispiel, wenn eine Schleife   verkettet eine zufällige Anzahl von   Strings der Benutzereingabe.

Ich denke, die Antwort ist "es kommt darauf an" - wenn Sie innerhalb einer Schleife mit mehr als einer Handvoll Iterationen verketten, wird ein StringBuilder fast immer eine bessere Leistung liefern, aber die einzige Möglichkeit, um sicher zu sein, ist ein Profil zu erstellen.


1
2018-02-15 11:11



Es gibt einen interessanten Artikel darüber bei Kodierung Horror. Jeff hat die folgenden Ergebnisse für 100.000 Iterationen auf einem Dual Core 3,5 GHz Core 2 Duo erhalten:

 Simple Concatenation    - 606 ms
 String.Format           - 665 ms
 string.Concat           - 587 ms
 String.Replace          - 979 ms
 StringBuilder           - 588 ms

1
2018-02-15 11:15



Von Dot Net Perls:

Wann verwende ich StringBuilder?

StringBuilder ist vollständig eine Optimierung und bietet keine anderen logischen Verbesserungen für den String Concat als seine interne Implementierung. Es ist jedoch wichtig, dass Sie es in Ihren Hochleistungsanwendungen und Websites richtig verwenden.

Manchmal ist es in Ordnung, kleine Schleifen von 4 oder weniger Iterationen mit einfachen String-Concats zu verwenden. In Grenzfällen kann dies jedoch katastrophal sein. Planen Sie Ihre Randfälle mit StringBuilder.


1
2018-02-15 12:01