Respostas:
Sim, a diferença de desempenho é significativa. Consulte o artigo da KB " Como melhorar o desempenho da concatenação de cadeias de caracteres no Visual C # ".
Eu sempre tentei codificar para obter clareza primeiro e depois otimizar o desempenho posteriormente. Isso é muito mais fácil do que fazer o contrário! No entanto, tendo visto a enorme diferença de desempenho em meus aplicativos entre os dois, agora penso nisso com um pouco mais de cuidado.
Felizmente, é relativamente simples executar uma análise de desempenho no seu código para ver onde você está gastando o tempo e modificá-lo para usá-lo StringBuilder
quando necessário.
Para esclarecer o que Gillian disse sobre 4 cordas, se você tiver algo parecido com isto:
string a,b,c,d;
a = b + c + d;
então seria mais rápido usando strings e o operador plus. Isso ocorre porque (como Java, como Eric aponta), ele usa internamente o StringBuilder automaticamente (na verdade, ele usa uma primitiva que o StringBuilder também usa)
No entanto, se o que você está fazendo é mais próximo:
string a,b,c,d;
a = a + b;
a = a + c;
a = a + d;
Então você precisa usar explicitamente um StringBuilder. O .Net não cria automaticamente um StringBuilder aqui, porque seria inútil. No final de cada linha, "a" deve ser uma sequência (imutável), para que seja necessário criar e dispor um StringBuilder em cada linha. Para velocidade, você precisará usar o mesmo StringBuilder até concluir a construção:
string a,b,c,d;
StringBuilder e = new StringBuilder();
e.Append(b);
e.Append(c);
e.Append(d);
a = e.ToString();
a
for uma variável local e o objeto que ele referenciar não tiver sido atribuído a alguma outra variável (que pode ser acessível a outro encadeamento), um bom otimizador poderá determinar que a
não é acessado por nenhum outro código durante essa sequência de linhas; apenas o valor final das a
questões. Portanto, poderia tratar essas três linhas de código como se elas fossem escritas a = b + c + d;
.
É preferível o StringBuilder se você estiver executando vários loops ou bifurcações na sua passagem de código ... no entanto, para obter um desempenho PURE, se você puder se safar com uma declaração de string ÚNICA , será muito mais eficiente.
Por exemplo:
string myString = "Some stuff" + var1 + " more stuff"
+ var2 + " other stuff" .... etc... etc...;
tem mais desempenho que
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..
Nesse caso, StringBuild pode ser considerado mais sustentável, mas não tem mais desempenho do que a declaração de string única.
9 vezes em 10, no entanto ... use o construtor de strings.
Em uma nota lateral: string + var também é mais eficiente que a string.Format (geralmente) que usa um StringBuilder internamente (em caso de dúvida ... verifique o refletor!)
Um exemplo simples para demonstrar a diferença de velocidade ao usar String
concatenação 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");
Resultado:
Usando concatenação de String: 15423 milissegundos
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");
Resultado:
Usando StringBuilder: 10 milissegundos
Como resultado, a primeira iteração levou 15423 ms enquanto a segunda iteração usando StringBuilder
levou 10 ms.
Parece-me que o uso StringBuilder
é mais rápido, muito mais rápido.
Essa referência mostra que a concatenação regular é mais rápida ao combinar 3 ou menos seqüências de caracteres.
http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/
O StringBuilder pode fazer uma melhoria muito significativa no uso da memória, especialmente no caso de adicionar 500 strings.
Considere o seguinte exemplo:
string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
buffer += i.ToString();
}
return buffer;
O que acontece na memória? As seguintes seqüências de caracteres são criadas:
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"
Adicionando esses cinco números ao final da string, criamos 13 objetos de string! E 12 deles eram inúteis! Uau!
StringBuilder corrige esse problema. Não é uma "sequência mutável", como costumamos ouvir ( todas as sequências no .NET são imutáveis ). Funciona mantendo um buffer interno, uma matriz de caracteres. Chamar Append () ou AppendLine () adiciona a string ao espaço vazio no final da matriz de caracteres; se a matriz for muito pequena, ela cria uma nova matriz maior e copia o buffer lá. Portanto, no exemplo acima, o StringBuilder pode precisar apenas de uma única matriz para conter todas as 5 adições à string - dependendo do tamanho do buffer. Você pode dizer ao StringBuilder qual o tamanho do buffer no construtor.
i.ToString()
. Portanto, com o StringBuilder, você ainda precisa criar 6 + 1 strings; reduziu a criação de 13 strings para a criação de 7 strings. Mas essa ainda é a maneira errada de encarar; a criação das seis seqüências numéricas não é relevante. Bottom line: você simplesmente não deveria ter mencionado as seis strings criadas por i.ToString()
; eles não fazem parte da comparação de eficiência.
Sim, StringBuilder
oferece melhor desempenho ao executar operações repetidas em uma string. Isso ocorre porque todas as alterações são feitas em uma única instância, para economizar muito tempo, em vez de criar uma nova instância como String
.
String
System
espaço para nomeStringBuilder
(sequência mutável)
System.Text
espaço para nomeArtigo altamente recomendado do dotnet mob: String vs. StringBuilder in C # .
Pergunta de estouro de pilha relacionado: Mutabilidade da string quando a string não muda em C #? .
String Vs String Builder:
A primeira coisa que você precisa saber é: em que assembléia essas duas classes vivem?
Assim,
string está presente no System
espaço para nome.
e
StringBuilder está presente no System.Text
espaço para nome.
Para declaração de string :
Você precisa incluir o System
espaço para nome. algo assim.
Using System;
e
Para declaração StringBuilder :
Você precisa incluir o System.text
espaço para nome. algo assim.
Using System.text;
Agora venha a pergunta real.
Qual é a diferença entre string e StringBuilder ?
A principal diferença entre esses dois é que:
string é imutável.
e
StringBuilder é mutável.
Então agora vamos discutir a diferença entre imutável e mutável
Mutável:: significa Mutável.
Imutável:: significa Não Alterável.
Por exemplo:
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."
}
}
}
Então, neste caso, vamos mudar o mesmo objeto 5 vezes.
Então a pergunta óbvia é essa! O que realmente acontece sob o capô, quando trocamos a mesma corda 5 vezes.
É o que acontece quando mudamos a mesma string 5 vezes.
vamos olhar para a figura.
Explicação:
Quando inicializamos essa variável "name" para "Rehan", ou seja, string name = "Rehan"
essa variável é criada na pilha "name" e aponta para o valor "Rehan". depois que esta linha é executada: "name = name +" Shah ". a variável de referência não está mais apontando para o objeto" Rehan ", agora está apontando para" Shah "e assim por diante.
O mesmo string
vale para o significado imutável de que, uma vez que criamos o objeto na memória, não podemos alterá-lo.
Então, quando concatenamos a name
variável, o objeto anterior permanece lá na memória e outro objeto de cadeia é criado ...
Portanto, a partir da figura acima, temos cinco objetos, os quatro objetos são jogados fora e não são usados. Eles ainda permanecem na memória e ocupam a quantidade de memória. "Garbage Collector" é responsável por isso, para limpar os recursos da memória.
Portanto, no caso de string a qualquer momento, quando manipulamos a string repetidamente, temos muitos objetos Criados e permanecemos lá na memória.
Então essa é a história da string Variable.
Agora vamos olhar para o objeto StringBuilder. Por exemplo:
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."
}
}
}
Então, neste caso, vamos mudar o mesmo objeto 5 vezes.
Então a pergunta óbvia é essa! O que realmente acontece sob o capô, quando mudamos o mesmo StringBuilder 5 vezes.
É o que acontece quando alteramos o mesmo StringBuilder 5 vezes.
Explicação: No caso do objeto StringBuilder. você não receberia o novo objeto. O mesmo objeto será alterado na memória, portanto, mesmo que você altere o objeto e digamos 10.000 vezes, ainda teremos apenas um objeto stringBuilder.
Você não possui muitos objetos de lixo ou objetos string_uilder não referenciados porque pode ser alterado. É mutável, ou seja, muda ao longo do tempo?
Diferenças:
StringBuilder reduz o número de alocações e atribuições, com um custo de memória extra usada. Utilizado corretamente, ele pode remover completamente a necessidade do compilador alocar cadeias cada vez maiores até que o resultado seja encontrado.
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
O desempenho de uma operação de concatenação para um objeto String ou StringBuilder depende da frequência com que ocorre uma alocação de memória. Uma operação de concatenação de String sempre aloca memória, enquanto uma operação de concatenação de StringBuilder somente aloca memória se o buffer do objeto StringBuilder for muito pequeno para acomodar os novos dados. Conseqüentemente, a classe String é preferível para uma operação de concatenação se um número fixo de objetos String for concatenado. Nesse caso, as operações de concatenação individuais podem até ser combinadas em uma única operação pelo compilador. Um objeto StringBuilder é preferível para uma operação de concatenação se um número arbitrário de seqüências de caracteres for concatenado; por exemplo, se um loop concatena um número aleatório de strings de entrada do usuário.
Fonte: MSDN
StringBuilder
é melhor para criar uma sequência a partir de muitos valores não constantes.
Se você estiver construindo uma sequência a partir de muitos valores constantes, como várias linhas de valores em um documento HTML ou XML ou outros trechos de texto, poderá anexar apenas a mesma sequência, porque quase todos os compiladores fazem isso. "dobragem constante", um processo de redução da árvore de análise quando você tem um monte de manipulação constante (também é usado quando você escreve algo parecido int minutesPerYear = 24 * 365 * 60
). E para casos simples com valores não constantes anexados um ao outro, o compilador .NET reduzirá seu código para algo semelhante ao que StringBuilder
faz.
Mas quando seu anexo não puder ser reduzido a algo mais simples pelo compilador, você desejará a StringBuilder
. Como salienta, é mais provável que isso aconteça dentro de um loop.
No .NET, o StringBuilder ainda é mais rápido que o acréscimo de cadeias. Tenho certeza de que, em Java, eles apenas criam um StringBuffer sob o capô quando você anexa strings, então não há realmente nenhuma diferença. Não sei por que eles ainda não fizeram isso no .NET.
Considere ' A triste tragédia do teatro de micro-otimização '.
O uso de seqüências de caracteres para concatenação pode levar a uma complexidade de tempo de execução na ordem de O(n^2)
.
Se você usar a StringBuilder
, há muito menos cópia da memória que precisa ser feita. Com oStringBuilder(int capacity)
você pode aumentar o desempenho se puder estimar o tamanho da final String
. Mesmo se você não for preciso, provavelmente precisará aumentar a capacidade StringBuilder
algumas vezes, o que também pode ajudar no desempenho.
Vi ganhos de desempenho significativos ao usar a EnsureCapacity(int capacity)
chamada de método em uma instância de StringBuilder
antes de usá-la para qualquer armazenamento de string. Eu costumo chamar isso na linha de código após a instanciação. Tem o mesmo efeito como se você instanciasse o StringBuilder
seguinte:
var sb = new StringBuilder(int capacity);
Essa chamada aloca a memória necessária antecipadamente, o que causa menos alocações de memória durante várias Append()
operações. Você precisa adivinhar qual a quantidade de memória necessária, mas para a maioria dos aplicativos isso não deve ser muito difícil. Geralmente erro do lado de muita memória (estamos falando 1k ou mais).
EnsureCapacity
logo após a StringBuilder
instanciação. Basta instanciar o StringBuilder
assim: var sb = new StringBuilder(int capacity)
.
Além das respostas anteriores, a primeira coisa que sempre faço ao pensar em problemas como esse é criar um pequeno aplicativo de teste. Dentro deste aplicativo, realize algum teste de sincronismo nos dois cenários e veja por si mesmo qual é o mais rápido.
IMHO, anexando mais de 500 entradas de string deve definitivamente usar o StringBuilder.
String e StringBuilder são realmente imutáveis, o StringBuilder possui buffers que permitem gerenciar seu tamanho com mais eficiência. Quando o StringBuilder precisa ser redimensionado é quando é re-alocado no heap. Por padrão, ele é dimensionado para 16 caracteres, você pode configurá-lo no construtor.
por exemplo.
StringBuilder sb = novo StringBuilder (50);
A concatenação de cadeias custará mais. Em Java, você pode usar StringBuffer ou StringBuilder com base em sua necessidade. Se você deseja uma implementação sincronizada e segura de thread, vá para StringBuffer. Isso será mais rápido que a concatenação de String.
Se você não precisa de implementação sincronizada ou segura de thread, vá para StringBuilder. Isso será mais rápido que a concatenação de String e também mais rápido que StringBuffer, pois não há sobrecarga de sincronização.
StringBuilder é provavelmente preferível. O motivo é que ele aloca mais espaço do que o necessário atualmente (você define o número de caracteres) para deixar espaço para anexos futuros. Os anexos futuros que se encaixam no buffer atual não exigem nenhuma alocação de memória ou coleta de lixo, o que pode ser caro. Em geral, eu uso o StringBuilder para concatentação de cadeias complexas ou formatação múltipla, depois converto para uma String normal quando os dados estão completos e quero um objeto imutável novamente.
Como regra geral, se eu tiver que definir o valor da sequência mais de uma vez ou se houver anexos à sequência, será necessário que ele seja um construtor de sequência. Eu já vi aplicativos que escrevi no passado antes de aprender sobre construtores de strings que tiveram uma enorme pegada de memória que parece continuar crescendo e crescendo. Alterar esses programas para usar o construtor de strings reduz significativamente o uso de memória. Agora juro pelo construtor de cordas.
Minha abordagem sempre foi usar o StringBuilder ao concatenar 4 ou mais seqüências de caracteres OU Quando não sei como podem ocorrer as concatenações.
StringBuilder
é significativamente mais eficiente, mas você não verá esse desempenho, a menos que esteja realizando uma grande quantidade de modificações em cadeias.
Abaixo está um rápido trecho de código para dar um exemplo do desempenho. Como você pode ver, você realmente começa a ver um grande aumento de desempenho quando entra em iterações grandes.
Como você pode ver, as 200.000 iterações levaram 22 segundos, enquanto as 1 milhão de iterações que utilizavam o StringBuilder
foram quase instantâneas.
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();
Resultado do código acima:
Iniciando String + em 28/01/2013 16:55:40.
String concluída + em 28/01/2013 16:55:40.
Iniciando String + em 28/01/2013 16:55:40.
String concluída + em 28/01/2013 16:56:02.
O início do Sb é anexado em 28/01/2013 16:56:02.
Anexo Sb concluído em 28/01/2013 16:56:02.
O StringBuilder terá um desempenho melhor, do ponto de vista da memória. Quanto ao processamento, a diferença no tempo de execução pode ser insignificante.