it-swarm-eu.dev

String vs. StringBuilder

Ich verstehe den Unterschied zwischen String und StringBuilder (StringBuilder ist veränderlich), aber gibt es einen großen Leistungsunterschied zwischen den beiden?

Das Programm, an dem ich arbeite, enthält viele fallbasierte String-Anhänge (500+). Ist die Verwendung von StringBuilder eine bessere Wahl?

204
Kuvo

Ja, der Leistungsunterschied ist erheblich. Weitere Informationen finden Sie im KB-Artikel " Verbessern der Zeichenfolgenverkettungsleistung in Visual C # ".

Ich habe immer versucht, zuerst Klarheit zu schaffen und später die Leistung zu optimieren. Das ist viel einfacher als umgekehrt! Nachdem ich jedoch den enormen Leistungsunterschied zwischen meinen Anwendungen gesehen habe, überlege ich mir das jetzt etwas genauer.

Glücklicherweise ist es relativ einfach, eine Leistungsanalyse für Ihren Code durchzuführen, um festzustellen, wo Sie die Zeit verbringen, und diese dann zu ändern, um StringBuilder zu verwenden, wo dies erforderlich ist.

225
Jay Bazuzi

Um zu verdeutlichen, was Gillian über 4 Saiten gesagt hat, wenn Sie so etwas haben:

string a,b,c,d;
 a = b + c + d;

dann wäre es mit Strings und dem Plus-Operator schneller. Dies liegt daran, dass (wie Java, wie Eric betont) StringBuilder intern automatisch verwendet wird (tatsächlich wird ein Grundelement verwendet, das auch von StringBuilder verwendet wird).

Wenn das, was Sie tun, jedoch näher ist an:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

Dann müssen Sie explizit einen StringBuilder verwenden. .Net erstellt hier nicht automatisch einen StringBuilder, da dies sinnlos wäre. Am Ende jeder Zeile muss "a" eine (unveränderbare) Zeichenfolge sein, sodass in jeder Zeile ein StringBuilder erstellt und angeordnet werden muss. Aus Gründen der Geschwindigkeit müssten Sie denselben StringBuilder verwenden, bis Sie mit dem Erstellen fertig sind:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();
54
James Curran

StringBuilder ist vorzuziehen WENN du machst mehrere Schleifen oder gibst deinen Code ein ... jedoch für die PURE-Leistung, wenn du mit einem - davonkommst SINGLE String-Deklaration, dann ist das viel performanter.

Beispielsweise:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

ist performanter als

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..

In diesem Fall kann StringBuild als wartbarer angesehen werden, ist jedoch nicht performanter als die Einzelzeichenfolgendeklaration.

9 mal von 10 ... benutze den String Builder.

Nebenbei bemerkt: string + var ist auch performanter als der string.Format-Ansatz (im Allgemeinen), bei dem ein StringBuilder intern verwendet wird (im Zweifelsfall ... Reflektor prüfen!)

28
calebjenkins

Dieser Benchmark zeigt, dass die regelmäßige Verkettung schneller ist, wenn 3 oder weniger Zeichenfolgen kombiniert werden.

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder kann die Speichernutzung erheblich verbessern, insbesondere wenn Sie 500 Zeichenfolgen addieren.

Betrachten Sie das folgende Beispiel:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

Was passiert im Gedächtnis? Die folgenden Zeichenfolgen werden erstellt:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"

Indem wir diese fünf Zahlen an das Ende der Zeichenkette anfügen, haben wir 13 Zeichenkettenobjekte erstellt! Und 12 von ihnen waren nutzlos! Wow!

StringBuilder behebt dieses Problem. Es ist keine "veränderbare Zeichenfolge", wie wir oft hören (, alle Zeichenfolgen in .NET sind unveränderlich ). Es funktioniert, indem ein interner Puffer, ein Array von Zeichen, gespeichert wird. Durch Aufrufen von Append () oder AppendLine () wird die Zeichenfolge dem leeren Bereich am Ende des char-Arrays hinzugefügt. Wenn das Array zu klein ist, erstellt es ein neues, größeres Array und kopiert den Puffer dorthin. Im obigen Beispiel benötigt StringBuilder daher möglicherweise nur ein einziges Array, das alle 5 Zusätze zum String enthält - abhängig von der Größe seines Puffers. Sie können StringBuilder mitteilen, wie groß der Puffer im Konstruktor sein soll.

23
Matt Trunnell

Ein einfaches Beispiel, um den Geschwindigkeitsunterschied bei der Verwendung von String Verkettung im Vergleich zu StringBuilder zu demonstrieren:

System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
    test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");

Ergebnis:

Verwenden der Zeichenfolgenverkettung: 15423 Millisekunden

StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
    test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");

Ergebnis:

Verwenden von StringBuilder: 10 Millisekunden

Infolgedessen dauerte die erste Iteration 15423 ms, während die zweite Iteration mit StringBuilder 10 ms dauerte.

Es scheint mir, dass die Verwendung von StringBuilder schneller ist, viel schneller.

21
Diizzy

Ja, StringBuilder bietet eine bessere Leistung, wenn eine Zeichenfolge wiederholt ausgeführt wird. Dies liegt daran, dass alle Änderungen an einer einzelnen Instanz vorgenommen werden, sodass viel Zeit gespart werden kann, anstatt eine neue Instanz wie String zu erstellen.

String Vs Stringbuilder

  • String

    1. unter System Namespace
    2. unveränderliche (schreibgeschützte) Instanz
    3. die Leistung verschlechtert sich, wenn sich der Wert ständig ändert
    4. thread sicher
  • StringBuilder (veränderbare Zeichenfolge)

    1. unter System.Text Namespace
    2. veränderliche Instanz
    3. zeigt eine bessere Leistung, da neue Änderungen an der vorhandenen Instanz vorgenommen werden

Ich kann den Dotnet Mob-Artikel nur empfehlen: String Vs StringBuilder in C # .

Verwandte Frage zum Stapelüberlauf: Änderbarkeit der Zeichenfolge, wenn sich die Zeichenfolge in C # nicht ändert? .

12
Shamseer K

StringBuilder reduziert die Anzahl der Zuweisungen und Zuweisungen und kostet zusätzlichen Speicher. Bei richtiger Anwendung muss der Compiler nicht mehr immer wieder größere Zeichenfolgen zuweisen, bis das Ergebnis gefunden wird.

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}

vs.

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once
8
moswald

Die Leistung eines Verkettungsvorgangs für ein String- oder StringBuilder-Objekt hängt davon ab, wie oft eine Speicherzuweisung erfolgt. Eine String-Verkettungsoperation reserviert immer Speicher, während eine StringBuilder-Verkettungsoperation nur dann Speicher reserviert, wenn der StringBuilder-Objektpuffer zu klein ist, um die neuen Daten aufzunehmen. Folglich ist die String-Klasse für eine Verkettungsoperation vorzuziehen, wenn eine feste Anzahl von String-Objekten verkettet ist. In diesem Fall können die einzelnen Verkettungsoperationen vom Compiler sogar zu einer einzigen Operation kombiniert werden. Ein StringBuilder-Objekt ist für eine Verkettungsoperation vorzuziehen, wenn eine beliebige Anzahl von Zeichenfolgen verkettet ist. Beispiel: Eine Schleife verkettet eine zufällige Anzahl von Zeichenfolgen für Benutzereingaben.

Quelle: MSDN

4
user487069

StringBuilder ist besser für den Aufbau eines Strings aus vielen nicht konstanten Werten.

Wenn Sie eine Zeichenfolge aus vielen konstanten Werten aufbauen, z. B. aus mehreren Zeilen von Werten in einem HTML- oder XML-Dokument oder anderen Textblöcken, müssen Sie nicht mehr nur an dieselbe Zeichenfolge anhängen, da dies bei fast allen Compilern der Fall ist "Konstante Faltung", ein Prozess zum Reduzieren des Analysebaums, wenn Sie eine Reihe konstanter Manipulationen ausführen (wird auch verwendet, wenn Sie etwas wie int minutesPerYear = 24 * 365 * 60 schreiben). Und für einfache Fälle mit nicht konstanten Werten, die aneinander angehängt sind, reduziert der .NET-Compiler Ihren Code auf etwas Ähnliches wie StringBuilder.

Wenn Ihr Append jedoch vom Compiler nicht auf etwas Einfacheres reduziert werden kann, benötigen Sie ein StringBuilder. Wie Fizch betont, ist es wahrscheinlicher, dass dies innerhalb einer Schleife geschieht.

3
JasonTrue
2
Jim G.

Die Verwendung von Zeichenfolgen zur Verkettung kann zu einer Laufzeitkomplexität in der Reihenfolge von O(n^2) führen.

Wenn Sie ein StringBuilder verwenden, muss viel weniger Speicher kopiert werden. Mit der StringBuilder(int capacity) können Sie die Leistung steigern, wenn Sie abschätzen können, wie groß das endgültige String sein wird. Selbst wenn Sie nicht genau sind, müssen Sie die Kapazität von StringBuilder wahrscheinlich nur ein paar Mal erhöhen, was ebenfalls zu einer Verbesserung der Leistung führen kann.

2
Steve g

Die Verwendung des Methodenaufrufs EnsureCapacity(int capacity) für eine Instanz von StringBuilder hat zu erheblichen Leistungssteigerungen geführt, bevor er für die Speicherung von Zeichenfolgen verwendet wurde. Ich bezeichne das normalerweise in der Codezeile nach der Instantiierung. Dies hat den gleichen Effekt, als würden Sie das StringBuilder folgendermaßen instanziieren:

var sb = new StringBuilder(int capacity);

Dieser Aufruf reserviert den benötigten Speicherplatz im Voraus, wodurch bei mehreren Append() Operationen weniger Speicherplatz reserviert wird. Sie müssen genau raten, wie viel Speicher Sie benötigen, aber für die meisten Anwendungen sollte dies nicht allzu schwierig sein. Ich irre mich normalerweise auf der Seite von etwas zu viel Gedächtnis (wir sprechen 1k oder so).

2
Jason Jackson

Ich glaube, dass StringBuilder schneller ist, wenn Sie mehr als 4 Zeichenfolgen haben, die Sie zusammenfügen müssen. Außerdem kann es einige coole Dinge wie AppendLine tun.

2
Gilligan

In .NET ist StringBuilder immer noch schneller als das Anhängen von Zeichenfolgen. Ich bin mir ziemlich sicher, dass sie in Java nur einen StringBuffer unter der Haube erstellen, wenn Sie Strings anhängen. Es gibt also keinen wirklichen Unterschied. Ich bin nicht sicher, warum sie dies in .NET noch nicht getan haben.

2
Eric Z Beard

String und StringBuilder sind eigentlich beide unveränderlich. Der StringBuilder verfügt über integrierte Puffer, mit denen seine Größe effizienter verwaltet werden kann. Wenn der StringBuilder die Größe ändern muss, wird er auf dem Heap neu zugewiesen. Standardmäßig ist die Größe auf 16 Zeichen festgelegt. Sie können dies im Konstruktor festlegen.

z.B.

StringBuilder sb = neuer StringBuilder (50);

1
capgpilk

Abgesehen von den vorherigen Antworten ist das erste, was ich bei solchen Problemen immer mache, eine kleine Testanwendung zu erstellen. Führen Sie in dieser App einige Zeittests für beide Szenarien durch und überzeugen Sie sich selbst, welche schneller sind.

IMHO, das Anhängen von mehr als 500 Zeichenfolgeneinträgen sollte auf jeden Fall StringBuilder verwenden.

1
RichS

Die Verkettung von Zeichenfolgen kostet Sie mehr. In Java können Sie je nach Bedarf entweder StringBuffer oder StringBuilder verwenden. Wenn Sie eine synchronisierte und thread-sichere Implementierung wünschen, wählen Sie StringBuffer. Dies ist schneller als die String-Verkettung.

Wenn Sie keine synchronisierte oder Thread-sichere Implementierung benötigen, entscheiden Sie sich für StringBuilder. Dies ist schneller als die Verkettung von Zeichenfolgen und auch schneller als StringBuffer, da kein Synchronisierungsaufwand entsteht.

1
raffimd

StringBuilder ist wesentlich effizienter, aber Sie werden diese Leistung nur dann sehen, wenn Sie eine große Menge an Zeichenfolgenänderungen vornehmen.

Im Folgenden finden Sie einen kurzen Codeabschnitt mit einem Beispiel für die Leistung. Wie Sie sehen, ist eine deutliche Leistungssteigerung erst zu beobachten, wenn Sie große Iterationen ausführen.

Wie Sie sehen, dauerten die 200.000 Iterationen 22 Sekunden, während die 1 Million Iterationen mit StringBuilder fast augenblicklich waren.

string s = string.Empty;
StringBuilder sb = new StringBuilder();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 50000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 200000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();
Console.WriteLine("Beginning Sb append at " + DateTime.Now.ToString());

for (int i = 0; i <= 1000000; i++)
{
    sb.Append("A");
}
Console.WriteLine("Finished Sb append at " + DateTime.Now.ToString());

Console.ReadLine();

Ergebnis des obigen Codes:

Zeichenfolge + beginnt am 28/01/2013 16:55:40.

Beendete Saite + am 28/01/2013 16:55:40.

Zeichenfolge + beginnt am 28/01/2013 16:55:40.

Beendete Saite + am 28/01/2013 16:56:02.

Beginn des Sb-Anhangs am 28.01.2013, 16:56:02 Uhr.

Beendetes Sb-Append am 28.01.2013 16:56:02.

0
CathalMF

Als Faustregel gilt: Wenn ich den Wert der Zeichenfolge mehr als einmal festlegen muss oder wenn der Zeichenfolge Anhänge hinzugefügt werden, muss es sich um einen Zeichenfolgengenerator handeln. Ich habe Anwendungen gesehen, die ich in der Vergangenheit geschrieben habe, bevor ich etwas über String-Builder gelernt habe, die einen riesigen Speicher-Footprint hatten, der immer weiter zu wachsen scheint. Durch Ändern dieser Programme zur Verwendung des Zeichenfolgengenerators wird die Speichernutzung erheblich reduziert. Jetzt schwöre ich beim Saitenbauer.

0
user13288

Mein Ansatz war es immer, StringBuilder zum Verketten von 4 oder mehr Zeichenfolgen zu verwenden OR Wenn ich nicht weiß, wie Verkettungen stattfinden sollen.

Guter leistungsbezogener Artikel dazu hier

0
JohnC

StringBuilder ist wahrscheinlich vorzuziehen. Der Grund dafür ist, dass mehr Speicherplatz zugewiesen wird, als derzeit benötigt wird (Sie legen die Anzahl der Zeichen fest), um Platz für zukünftige Anhänge zu lassen. Dann erfordern die zukünftigen Anhänge, die in den aktuellen Puffer passen, keine Speicherzuweisung oder Speicherbereinigung, was teuer sein kann. Im Allgemeinen verwende ich StringBuilder für komplexe Zeichenfolgenkonzatentierung oder Mehrfachformatierung. Wenn die Daten vollständig sind, konvertiere ich sie in eine normale Zeichenfolge und möchte wieder ein unveränderliches Objekt.

0
deemer

Wenn Sie häufig Zeichenfolgen verketten, verwenden Sie einen StringBuilder. Wenn Sie mit einer Zeichenfolge verketten, erstellen Sie jedes Mal eine neue Zeichenfolge, wodurch mehr Speicher belegt wird.

Alex

0
Alex Fort