Risposte:
Sì, la differenza di prestazioni è significativa. Vedi l'articolo KB " Come migliorare le prestazioni di concatenazione di 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 usarlo StringBuilder
dove necessario.
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();
a
è una variabile locale e l'oggetto a cui fa riferimento non è stato assegnato a qualche altra variabile (che potrebbe essere accessibile a un altro thread), un buon ottimizzatore potrebbe determinare che a
non è accessibile da nessun altro codice durante questa sequenza di Linee; solo il valore finale delle a
cose. Quindi potrebbe trattare queste tre righe di codice come se fossero state scritte a = b + c + d;
.
StringBuilder è preferibile SE stai eseguendo più loop o forchette nel tuo pass di codice ... tuttavia, per prestazioni PURE, se riesci a cavartela con un SINGOLO dichiarazione di stringa, allora è 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!)
Un semplice esempio per dimostrare la differenza di velocità quando si utilizza la String
concatenazione rispetto a 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 impiegava 15423 ms mentre la seconda iterazione usando StringBuilder
impiegava 10 ms.
Mi sembra che l'utilizzo StringBuilder
sia più veloce, molto più veloce.
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.
i.ToString()
. Quindi con StringBuilder, devi ancora creare 6 + 1 stringhe; ha ridotto la creazione di 13 stringhe alla creazione di 7 stringhe. Ma quello è ancora il modo sbagliato di guardarlo; la creazione delle sei stringhe numeriche non è rilevante. In conclusione: semplicemente non avresti dovuto menzionare le sei stringhe create da i.ToString()
; non fanno parte del confronto di efficienza.
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 comeString
.
String
System
spazio dei nomiStringBuilder
(stringa mutabile)
System.Text
spazio dei nomiConsiglio 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 #? .
String Vs String Builder:
Prima cosa che devi sapere che in quale assemblea vivono queste due classi?
Così,
stringa è presente nello System
spazio dei nomi.
e
StringBuilder è presente nello System.Text
spazio dei nomi.
Per la dichiarazione di stringa :
Devi includere lo System
spazio dei nomi. qualcosa come questo.
Using System;
e
Per la dichiarazione StringBuilder :
Devi includere lo System.text
spazio dei nomi. qualcosa come questo.
Using System.text;
Ora vieni la vera domanda.
Qual è la differenza tra string e StringBuilder ?
La differenza principale tra questi due è che:
la stringa è immutabile.
e
StringBuilder è modificabile.
So Now consente di discutere la differenza tra immutabile e mutevole
Mutabile: significa modificabile.
Immutabile: significa non modificabile.
Per 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 effettivamente sotto il cofano, quando cambiamo la stessa stringa 5 volte.
Questo è ciò che accade quando cambiamo la stessa stringa 5 volte.
guardiamo la figura.
spiegazione:
Quando inizializziamo per la prima volta questa variabile "nome" su "Rehan", ad es 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 significato che una volta creato l'oggetto nella memoria non possiamo cambiarlo.
Quindi quando concateniamo la name
variabile 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ì nella memoria.
Quindi questa è la storia della stringa Variable.
Ora diamo un'occhiata all'oggetto StringBuilder. Per 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.
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 garbage o oggetti stringBuilder non referenziati perché possono essere cambiati. È mutevole, nel senso che cambia nel tempo?
differenze:
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
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 degli oggetti 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
StringBuilder
è meglio per creare una stringa da molti valori non costanti.
Se stai costruendo 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 mucchio di manipolazioni costanti (viene anche utilizzato quando si scrive qualcosa di simile 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 StringBuilder
fa.
Ma quando il compilatore non può ridurre la tua aggiunta a qualcosa di più semplice, ti consigliamo di StringBuilder
. Come sottolinea Fizch, è più probabile che accada all'interno di un ciclo.
In .NET, StringBuilder è ancora più veloce dell'aggiunta di stringhe. Sono abbastanza sicuro che in Java, creino un 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.
Considera " La triste tragedia del teatro della micro-ottimizzazione ".
L'uso di stringhe per la concatenazione può portare a una complessità di runtime nell'ordine di O(n^2)
.
Se si utilizza a StringBuilder
, è necessario copiare molto meno la memoria. Con questo StringBuilder(int capacity)
puoi aumentare le prestazioni se puoi stimare quanto sarà grande la finale String
. Anche se non sei preciso, probabilmente dovrai solo aumentare la capacità di StringBuilder
un paio di volte, il che può aiutare anche le prestazioni.
Ho visto significativi miglioramenti delle prestazioni usando la EnsureCapacity(int capacity)
chiamata del metodo su un'istanza di StringBuilder
prima di usarla per qualsiasi archiviazione di stringhe. Di solito lo chiamo sulla riga di codice dopo l'istanza. Ha lo stesso effetto di un'istanza StringBuilder
come questa:
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 ti servirà, 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ì).
EnsureCapacity
subito dopo l' StringBuilder
istanza. Semplicemente un'istanza StringBuilder
in questo modo: var sb = new StringBuilder(int capacity)
.
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.
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 riassegnato sull'heap. Di default ha una dimensione di 16 caratteri, puoi impostarlo nel costruttore.
per esempio.
StringBuilder sb = new StringBuilder (50);
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.
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.
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.
Il mio approccio è sempre stato quello di utilizzare StringBuilder durante la concatenazione di 4 o più stringhe OPPURE Quando non so come possono avvenire le concatenazioni.
StringBuilder
è significativamente più efficiente ma non vedrai quella prestazione a meno che 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 che utilizzavano 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.
StringBuilder avrà prestazioni migliori, dal punto di vista della memoria. Per quanto riguarda l'elaborazione, la differenza nel tempo di esecuzione può essere trascurabile.