it-swarm.it

String vs. StringBuilder

Capisco la differenza tra String e StringBuilder (StringBuilder essendo mutabile) ma c'è una grande differenza di prestazioni tra i due?

Il programma a cui sto lavorando ha molti aggiunte di stringhe guidate da maiuscole (500+). Usare StringBuilder è una scelta migliore?

202
Kuvo

Sì, la differenza di prestazioni è significativa. Vedi l'articolo KB " Come migliorare le prestazioni di concatenazione delle stringhe in Visual C # ".

Ho sempre cercato di programmare prima la chiarezza e poi di ottimizzare le prestazioni in seguito. È molto più facile che farlo al contrario! Tuttavia, dopo aver visto l'enorme differenza di prestazioni nelle mie applicazioni tra i due, ora ci penso un po 'più attentamente.

Fortunatamente, è relativamente semplice eseguire l'analisi delle prestazioni sul codice per vedere dove stai spendendo il tempo e quindi modificarlo per utilizzare StringBuilder dove necessario.

224
Jay Bazuzi

Per chiarire cosa ha detto Gillian a proposito di 4 corde, se hai qualcosa del genere:

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

allora sarebbe più veloce usando le stringhe e l'operatore più. Questo perché (come Java, come sottolinea Eric), utilizza internamente StringBuilder automaticamente (in realtà, utilizza una primitiva che utilizza anche StringBuilder)

Tuttavia, se quello che stai facendo è più vicino a:

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

Quindi è necessario utilizzare esplicitamente un StringBuilder. .Net non crea automaticamente un StringBuilder qui, perché sarebbe inutile. Alla fine di ogni riga, "a" deve essere una stringa (immutabile), quindi dovrebbe creare e disporre un StringBuilder su ogni riga. Per la velocità, dovresti usare lo stesso StringBuilder fino a quando non hai finito di costruire:

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 è preferibile IF stai facendo più loop o forchette nel tuo pass di codice ... tuttavia, per prestazioni PURE, se riesci a cavartela con un SINGLE = dichiarazione di stringa, quindi è molto più performante.

Per esempio:

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

è più performante di

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 questo caso, StringBuild potrebbe essere considerato più gestibile, ma non è più performante della singola dichiarazione di stringa.

9 volte su 10 però ... usa il generatore di stringhe.

Nota a margine: string + var è anche più performante dell'approccio string.Format (generalmente) che usa internamente uno StringBuilder (in caso di dubbi ... controlla il riflettore!)

28
calebjenkins

Questo benchmark mostra che la concatenazione regolare è più veloce quando si combinano 3 o meno stringhe.

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

StringBuilder può apportare un miglioramento molto significativo nell'utilizzo della memoria, specialmente nel caso in cui si sommino 500 stringhe.

Considera il seguente esempio:

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

Cosa succede nella memoria? Vengono create le seguenti stringhe:

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"

Aggiungendo quei cinque numeri alla fine della stringa abbiamo creato 13 oggetti stringa! E 12 di loro erano inutili! Wow!

StringBuilder risolve questo problema. Non è una "stringa mutabile" come spesso sentiamo ( tutte le stringhe in .NET sono immutabili ). Funziona mantenendo un buffer interno, un array di caratteri. Chiamare Append () o AppendLine () aggiunge la stringa allo spazio vuoto alla fine dell'array char; se l'array è troppo piccolo, crea un nuovo array più grande e copia lì il buffer. Quindi nell'esempio sopra, StringBuilder potrebbe aver bisogno di un solo array per contenere tutte e 5 le aggiunte alla stringa, a seconda della dimensione del suo buffer. Puoi dire a StringBuilder quanto deve essere grande il suo buffer nel costruttore.

23
Matt Trunnell

Un semplice esempio per dimostrare la differenza di velocità quando si utilizza la concatenazione String vs StringBuilder:

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");

Risultato:

Utilizzo della concatenazione di stringhe: 15423 millisecondi

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");

Risultato:

Utilizzando StringBuilder: 10 millisecondi

Di conseguenza, la prima iterazione ha impiegato 15423 ms mentre la seconda iterazione usando StringBuilder ha impiegato 10 ms.

Mi sembra che l'uso di StringBuilder sia più veloce, molto più veloce.

19
Diizzy

Sì, StringBuilder offre prestazioni migliori durante l'esecuzione di operazioni ripetute su una stringa. È perché tutte le modifiche vengono apportate a una singola istanza in modo da poter risparmiare molto tempo invece di creare una nuova istanza come String.

String Vs Stringbuilder

  • String

    1. sotto lo spazio dei nomi System
    2. istanza immutabile (sola lettura)
    3. le prestazioni diminuiscono quando si verifica una variazione continua del valore
    4. filo sicuro
  • StringBuilder (stringa modificabile)

    1. sotto lo spazio dei nomi System.Text
    2. istanza mutabile
    3. mostra prestazioni migliori poiché vengono apportate nuove modifiche all'istanza esistente

Consiglio vivamente l'articolo mob dotnet: String Vs StringBuilder in C # .

Domanda di overflow dello stack correlata: Mutabilità della stringa quando la stringa non cambia in C #? .

11
Shamseer K

StringBuilder riduce il numero di allocazioni e assegnazioni, a un costo aggiuntivo di memoria utilizzata. Se usato correttamente, può rimuovere completamente la necessità che il compilatore assegni continuamente stringhe sempre più grandi fino a quando non viene trovato il risultato.

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

String Vs String Builder:

Prima cosa che devi sapere che in quale Assemblea vivono queste due classi?

Così,

stringa è presente nello spazio dei nomi System.

e

StringBuilder è presente nello spazio dei nomi System.Text.

Per la dichiarazione stringa :

Devi includere lo spazio dei nomi System. qualcosa come questo. Using System;

e

Per la dichiarazione StringBuilder :

Devi includere lo spazio dei nomi System.text. qualcosa come questo. Using System.text;

Ora vieni la vera domanda.

Qual è la differenza tra string & StringBuilder ?

La differenza principale tra questi due è che:

stringa è immutabile.

e

StringBuilder è modificabile.

Quindi ora discutiamo della differenza tra immutabile e mutabile

Mutabile: : significa Modificabile.

Immutabile: : significa Non modificabile.

Ad esempio:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}

Quindi, in questo caso, cambieremo lo stesso oggetto 5 volte.

Quindi la domanda ovvia è quella! Cosa succede realmente sotto il cofano, quando cambiamo la stessa stringa 5 volte.

Questo è ciò che accade quando cambiamo la stessa stringa 5 volte.

guardiamo la figura.

enter image description here

analitico:

Quando inizializziamo per la prima volta questa variabile "nome" su "Rehan" i-e string name = "Rehan" questa variabile viene creata nello stack "nome" e punta a quel valore "Rehan". dopo che questa riga è stata eseguita: "name = name +" Shah ". la variabile di riferimento non punta più a quell'oggetto" Rehan "ora punta a" Shah "e così via.

Quindi string è immutabile, il che significa che una volta creato l'oggetto in memoria non possiamo cambiarlo.

Quindi quando concateniamo la variabile name l'oggetto precedente rimane lì nella memoria e viene creato un altro nuovo oggetto stringa ...

Quindi dalla figura sopra abbiamo cinque oggetti i quattro oggetti che vengono gettati via non vengono usati affatto. Rimangono nella memoria e occultano la quantità di memoria. "Garbage Collector" è responsabile di ciò così pulito che le risorse dalla memoria.

Quindi in caso di stringa ogni volta che manipoliamo la stringa più e più volte abbiamo alcuni oggetti creati e rimaniamo lì in memoria.

Quindi questa è la storia della stringa Variable.

Ora diamo un'occhiata all'oggetto StringBuilder. Ad esempio:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}

Quindi, in questo caso, cambieremo lo stesso oggetto 5 volte.

Quindi la domanda ovvia è quella! Cosa succede realmente sotto il cofano, quando cambiamo lo stesso StringBuilder 5 volte.

Questo è ciò che accade quando cambiamo lo stesso StringBuilder 5 volte.

guardiamo la figura. enter image description here

Spiegazione: In caso di oggetto StringBuilder. non otterrai il nuovo oggetto. Lo stesso oggetto cambierà in memoria, quindi anche se si cambia l'oggetto e diciamo 10.000 volte avremo ancora un solo oggetto stringBuilder.

Non hai molti oggetti spazzatura o oggetti string_uferenziati non referenziati perché possono essere cambiati. È mutevole, nel senso che cambia nel tempo?

Differenze:

  • String è presente nello spazio dei nomi di sistema dove Stringbuilder è presente nello spazio dei nomi System.Text.
  • string è immutabile laddove StringBuilder è mutabe.
4
Rehan Shah

Le prestazioni di un'operazione di concatenazione per un oggetto String o StringBuilder dipendono dalla frequenza con cui si verifica un'allocazione di memoria. Un'operazione di concatenazione di stringhe alloca sempre la memoria, mentre un'operazione di concatenazione di StringBuilder alloca memoria solo se il buffer dell'oggetto StringBuilder è troppo piccolo per contenere i nuovi dati. Di conseguenza, la classe String è preferibile per un'operazione di concatenazione se viene concatenato un numero fisso di oggetti String. In tal caso, le singole operazioni di concatenazione potrebbero anche essere combinate in un'unica operazione dal compilatore. Un oggetto StringBuilder è preferibile per un'operazione di concatenazione se viene concatenato un numero arbitrario di stringhe; ad esempio, se un ciclo concatena un numero casuale di stringhe di input dell'utente.

Fonte: MSDN

4
user487069

StringBuilder è migliore per creare una stringa da molti valori non costanti.

Se stai creando una stringa da molti valori costanti, come più righe di valori in un documento HTML o XML o altri blocchi di testo, puoi evitare di aggiungere semplicemente la stessa stringa, perché quasi tutti i compilatori lo fanno "ribaltamento costante", un processo di riduzione dell'albero di analisi quando si ha un sacco di manipolazione costante (viene anche utilizzato quando si scrive qualcosa come int minutesPerYear = 24 * 365 * 60). E per casi semplici con valori non costanti aggiunti l'uno all'altro, il compilatore .NET ridurrà il codice a qualcosa di simile a quello che fa StringBuilder.

Ma quando la tua appendice non può essere ridotta a qualcosa di più semplice dal compilatore, vorrai un StringBuilder. Come sottolinea Fizch, è più probabile che accada all'interno di un ciclo.

3
JasonTrue
2
Jim G.

L'uso di stringhe per la concatenazione può comportare una complessità di runtime nell'ordine di O(n^2).

Se si utilizza StringBuilder, è necessario eseguire molte meno copie della memoria. Con StringBuilder(int capacity) è possibile aumentare le prestazioni se è possibile stimare la dimensione finale di String. Anche se non sei preciso, probabilmente dovrai aumentare la capacità di StringBuilder un paio di volte, il che può aiutare anche le prestazioni.

2
Steve g

Ho visto significativi miglioramenti delle prestazioni utilizzando la chiamata del metodo EnsureCapacity(int capacity) su un'istanza di StringBuilder prima di utilizzarla per qualsiasi archiviazione di stringhe. Di solito lo chiamo sulla riga di codice dopo l'istanza. Ha lo stesso effetto di un'istanza di StringBuilder in questo modo:

var sb = new StringBuilder(int capacity);

Questa chiamata alloca la memoria necessaria in anticipo, il che provoca meno allocazioni di memoria durante più Append() operazioni. Devi fare un'ipotesi ponderata su quanta memoria avrai bisogno, ma per la maggior parte delle applicazioni questo non dovrebbe essere troppo difficile. Di solito sbaglio sul lato di un po 'troppo di memoria (stiamo parlando 1k o giù di lì).

2
Jason Jackson

Credo che StringBuilder sia più veloce se hai più di 4 stringhe che devi aggiungere insieme. Inoltre può fare cose interessanti come AppendLine.

2
Gilligan

In .NET, StringBuilder è ancora più veloce dell'aggiunta di stringhe. Sono abbastanza sicuro che in Java, creino uno StringBuffer sotto il cofano quando aggiungi le stringhe, quindi non c'è davvero alcuna differenza. Non sono sicuro del perché non lo abbiano ancora fatto in .NET.

2
Eric Z Beard

String e StringBuilder sono in realtà entrambi immutabili, StringBuilder ha buffer integrati che consentono di gestire le sue dimensioni in modo più efficiente. Quando StringBuilder deve essere ridimensionato è quando viene allocato nuovamente nell'heap. Per impostazione predefinita, ha una dimensione di 16 caratteri, è possibile impostarlo nel costruttore.

per esempio.

StringBuilder sb = new StringBuilder (50);

1
capgpilk

Oltre alle risposte precedenti, la prima cosa che faccio sempre quando penso a problemi come questo è creare una piccola applicazione di prova. All'interno di questa app, esegui alcuni test di temporizzazione per entrambi gli scenari e vedi di persona quale è più veloce.

IMHO, l'aggiunta di oltre 500 voci di stringa dovrebbe sicuramente utilizzare StringBuilder.

1
RichS

La concatenazione di stringhe ti costerà di più. In Java, è possibile utilizzare StringBuffer o StringBuilder in base alle proprie esigenze. Se vuoi un'implementazione sincronizzata e sicura dei thread, scegli StringBuffer. Questo sarà più veloce della concatenazione di stringhe.

Se non hai bisogno dell'implementazione sincronizzata o sicura dei thread, scegli StringBuilder. Questo sarà più veloce della concatenazione di stringhe e anche più veloce di StringBuffer poiché il loro non è un sovraccarico di sincronizzazione.

1
raffimd

StringBuilder è significativamente più efficiente ma non vedrai quella prestazione a meno che tu non stia facendo una grande quantità di modifica della stringa.

Di seguito è riportato un breve pezzo di codice per dare un esempio delle prestazioni. Come puoi vedere, inizi a vedere un notevole aumento delle prestazioni solo quando entri in grandi iterazioni.

Come puoi vedere, le 200.000 iterazioni impiegarono 22 secondi mentre le 1 milione di iterazioni usando StringBuilder erano quasi istantanee.

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();

Risultato del codice sopra:

Inizio stringa + al 28/01/2013 alle 16:55:40.

Corda finita + al 28/01/2013 alle 16:55:40.

Inizio stringa + al 28/01/2013 alle 16:55:40.

Corda finita + al 28/01/2013 alle 16:56:02.

A partire da Sb append al 28/01/2013 alle 16:56:02.

Appendice Sb terminata il 28/01/2013 alle 16:56:02.

0
CathalMF

Come regola generale, se devo impostare il valore della stringa più di una volta o se ci sono aggiunte alla stringa, allora deve essere un generatore di stringhe. Ho visto applicazioni che ho scritto in passato prima di conoscere costruttori di stringhe che hanno avuto un'enorme impronta di memoria che sembra continuare a crescere e crescere. La modifica di questi programmi per utilizzare il generatore di stringhe riduce notevolmente l'utilizzo della memoria. Ora lo giuro sul costruttore di stringhe.

0
user13288

Il mio approccio è sempre stato quello di utilizzare StringBuilder durante la concatenazione di 4 o più stringhe OR Quando non so come possono avvenire le concatenazioni.

Articolo relativo alle buone prestazioni qui

0
JohnC

StringBuilder è probabilmente preferibile. Il motivo è che alloca più spazio del necessario (si imposta il numero di caratteri) per lasciare spazio a futuri accodamenti. Quindi quei futuri accodamenti che si adattano al buffer corrente non richiedono alcuna allocazione di memoria o garbage collection, che può essere costoso. In generale, utilizzo StringBuilder per concatenazioni di stringhe complesse o formattazioni multiple, quindi converto in una stringa normale quando i dati sono completi e desidero di nuovo un oggetto immutabile.

0
deemer

Se stai eseguendo molte concatenazioni di stringhe, utilizza StringBuilder. Quando si concatena con una stringa, si crea una nuova stringa ogni volta, utilizzando più memoria.

Alex

0
Alex Fort