Qual é a maneira mais eficiente de concatenar seqüências de caracteres?
c#
.net
string
optimization
jimmij
fonte
fonte
StringBuilder
casos de uso podem ser encontradas aqui .String.Format
em esteróides. O que, em termos de desempenho, é um pouco mais lento em um liners do que+
eString.Concat
, mas muito melhor do que aqueles, embora mais lento do queStringBuilder
em várias chamadas. Na prática, as diferenças de desempenho são tais que, se eu tivesse que escolher apenas uma maneira de concatenar, escolheria interpolações de strings usando$
... Se duas maneiras, adicioneStringBuilder
à minha caixa de ferramentas. Com essas duas maneiras que você está definido.String.Join
resposta abaixo não faz+
justiça e é, na prática, uma péssima maneira de concatenar strings, mas é surpreendentemente rápida em termos de desempenho. A resposta porque é interessante.String.Concat
eString.Join
ambos podem atuar em matrizes, masString.Join
na verdade são mais rápidos. Aparentemente,String.Join
é bastante sofisticado e mais otimizado do queString.Concat
, em parte porque opera de maneira semelhante aoStringBuilder
que calcula primeiro o comprimento da string e depois constrói a string que se beneficia desse conhecimento usando o UnSafeCharBuffer.String.Join
também requer a construção de uma matriz que parece ineficiente, certo? ... Acontece que,+
e deString.Concat
qualquer maneira, constrói matrizes para seus constituintes. Conseqüentemente, criar manualmente uma matriz e alimentá-laString.Join
é comparativamente mais rápido ... no entanto,StringBuilder
ainda superaString.Join
em todos os aspectos práticos, enquanto$
é apenas um pouco mais lento e muito mais rápido em longas seqüências de caracteres ... para não mencionar que é complicado e feio de usarString.Join
se você tiver para criar uma matriz para ele no local.Respostas:
O
StringBuilder.Append()
método é muito melhor do que usar o+
operador. Mas descobri que, ao executar 1000 concatenações ou menos,String.Join()
é ainda mais eficiente queStringBuilder
.O único problema com
String.Join
é que você precisa concatenar as seqüências com um delimitador comum.Edit: como apontou @ryanversaw , você pode fazer o delimitador
string.Empty
.fonte
StringBuilder
tem um enorme custo inicial comparável, só é eficiente quando usado com cadeias muito grandes ou com muitas concatenações. Não é trivial descobrir qualquer situação. Se o desempenho for um problema, a criação de perfil é seu amigo (consulte ANTS).string.Concat
?Rico Mariani , o guru do .NET Performance, tinha um artigo sobre esse assunto. Não é tão simples quanto se pode suspeitar. O conselho básico é este:
Ainda outro artigo para apoiar essa afirmação vem de Eric Lippert, onde ele descreve as otimizações executadas em
+
concatenações de uma linha de maneira detalhada.fonte
Existem 6 tipos de concatenações de strings:
+
símbolo de mais ( ).string.Concat()
.string.Join()
.string.Format()
.string.Append()
.StringBuilder
.Em um experimento, ficou provado que
string.Concat()
é a melhor maneira de abordar se as palavras são menores que 1000 (aproximadamente) e se as palavras são maiores que 1000, entãoStringBuilder
devem ser usadas.Para mais informações, consulte este site .
fonte
+
na verdade era 3 milissegundos mais rápido do questring.Concat()
, embora eu não tenha examinado a quantidade de strings necessárias antes dosstring.Concat()
outraces+
.De Chinh Do - StringBuilder nem sempre é mais rápido :
Regras de ouro
Ao concatenar três valores de sequência dinâmica ou menos, use a concatenação tradicional de sequência.
Ao concatenar mais de três valores de sequência dinâmica, use
StringBuilder
.Ao criar uma cadeia grande a partir de vários literais, use o
@
literal de cadeia ou o operador inline +.Na maioria das vezes,
StringBuilder
é a sua melhor aposta, mas há casos, como mostrado nesse post, em que você deve pelo menos pensar em cada situação.fonte
Se você estiver operando em loop,
StringBuilder
provavelmente é o caminho a percorrer; economiza a sobrecarga de criar novas seqüências regularmente. No código que será executado apenas uma vez, no entanto,String.Concat
provavelmente está bem.No entanto, Rico Mariani (guru de otimização do .NET) elaborou um questionário no qual afirmou no final que, na maioria dos casos, ele recomenda
String.Format
.fonte
Aqui está o método mais rápido que desenvolvi ao longo de uma década para meu aplicativo PNL em larga escala. Eu tenho variações para
IEnumerable<T>
e outros tipos de entrada, com e sem separadores de tipos diferentes (Char
,String
), mas aqui mostro o caso simples de concatenar todas as strings de uma matriz em uma única string, sem separador. A versão mais recente aqui é desenvolvida e testada em unidade no C # 7 e .NET 4.7 .Existem duas chaves para maior desempenho; o primeiro é pré-calcular o tamanho total exato necessário. Esta etapa é trivial quando a entrada é uma matriz, como mostrado aqui. Para manipulação
IEnumerable<T>
, vale a pena reunir primeiro as seqüências de caracteres em uma matriz temporária para calcular esse total (a matriz é necessária para evitar a chamadaToString()
mais de uma vez por elemento, pois tecnicamente, dada a possibilidade de efeitos colaterais, isso pode alterar a semântica esperada de uma operação 'junção de cadeia').Em seguida, dado o tamanho total da alocação da sequência final, o maior aumento no desempenho é obtido com a construção da sequência de resultados no local . Isso exige a técnica (talvez controversa) de suspender temporariamente a imutabilidade de um novo
String
que é inicialmente alocado cheio de zeros. Qualquer controvérsia à parte, no entanto ...Código completo:
Devo mencionar que este código tem uma ligeira modificação do que eu me uso. No original, chamo a instrução IL cpblk do C # para fazer a cópia real. Por simplicidade e portabilidade no código aqui, substituí-o por P / Invoke
memcpy
, como você pode ver. Para obter o melhor desempenho em x64 ( mas talvez não em x86 ), convém usar o método cpblk .fonte
string.Join
já faz todas essas coisas para você. Não há necessidade de escrever você mesmo. Ele calcula o tamanho da sequência final, constrói uma sequência desse tamanho e depois grava na matriz de caracteres subjacente. Ele ainda tem o bônus de usar nomes de variáveis legíveis no processo.String.Join
pode ser eficiente. Como sugeri na introdução, o código aqui é apenas a ilustração mais simples de uma família de funções que utilizo para cenários queString.Join
não tratam (como otimizar paraChar
separador) ou não nas versões anteriores do .NET. Suponho que não deveria ter escolhido isso pelo exemplo mais simples, pois é um caso queString.Join
já lida bem, embora com a "ineficiência", provavelmente incomensurável, de processar um separador vazio, a saber.String.Empty
.Concat
, o que também faz isso corretamente. De qualquer maneira, você não precisa escrever o código sozinho.String.Join
versus o meu código usando este equipamento de teste . Para 10 milhões de operações de concatenação aleatória de até 100 seqüências de caracteres de tamanho cada, o código mostrado acima é consistentemente 34% mais rápido do queString.Join
na versão x64 criada com o .NET 4.7 . Como o OP solicita explicitamente o método "mais eficiente", o resultado sugere que minha resposta se aplica. Se isso abordar suas preocupações, convido você a reconsiderar seu voto negativo.Neste artigo do MSDN :
Portanto, se você confia no MSDN, vá com o StringBuilder se precisar executar mais de 10 operações / concatenações de strings - caso contrário, concatenar simples com o '+' é bom.
fonte
Também é importante ressaltar que você deve usar o
+
operador se estiver concatenando literais de string .Como concatenar várias seqüências de caracteres (Guia de Programação em C #)
fonte
Além das outras respostas, lembre-se de que o StringBuilder pode receber uma quantidade inicial de memória para alocar .
Anexar repetidamente a um StringBuilder que não foi pré-alocado pode resultar em muitas alocações desnecessárias, assim como concatenar repetidamente seqüências regulares.
Se você sabe quanto tempo a string final será, pode calculá-la trivialmente ou pode fazer um palpite sobre o caso comum (alocar demais não é necessariamente uma coisa ruim), você deve fornecer essas informações ao construtor ou ao Propriedade de capacidade . Especialmente ao executar testes de desempenho para comparar o StringBuilder com outros métodos, como o String.Concat, que fazem a mesma coisa internamente. Qualquer teste que você vê online que não inclui a pré-alocação do StringBuilder em suas comparações está errado.
Se você não consegue adivinhar o tamanho, provavelmente está escrevendo uma função de utilitário que deve ter seu próprio argumento opcional para controlar a pré-alocação.
fonte
A seguir, pode ser mais uma solução alternativa para concatenar várias seqüências de caracteres.
interpolação de string
fonte
String.Format
mas mais legível e fácil de trabalhar. Marcando-o como benchmark, é um pouco mais lento que+
eString.Concat
em uma linha de concatenações, mas muito melhor do que aqueles em chamadas repetidas, tornandoStringBuilder
menos necessário.O mais eficiente é usar o StringBuilder, assim:
@jonezy: String.Concat é bom se você tiver algumas coisas pequenas. Mas se você estiver concatenando megabytes de dados, é provável que o seu programa seja tanque.
fonte
Experimente estes 2 pedaços de código e você encontrará a solução.
Vs
Você descobrirá que o 1º código terminará muito rápido e a memória estará em boa quantidade.
O segundo código talvez a memória esteja ok, mas levará mais tempo ... muito mais tempo. Portanto, se você tem um aplicativo para muitos usuários e precisa de velocidade, use o primeiro. Se você tem um aplicativo para um aplicativo de um usuário por um período curto, talvez possa usar os dois ou o segundo será mais "natural" para os desenvolvedores.
Felicidades.
fonte
Por apenas duas strings, você definitivamente não deseja usar o StringBuilder. Há um limite acima do qual a sobrecarga de StringBuilder é menor que a sobrecarga de alocar várias seqüências.
Portanto, para mais de 2 a 3 cordas, use o código do DannySmurf . Caso contrário, basta usar o operador +.
fonte
System.String é imutável. Quando modificamos o valor de uma variável de cadeia, uma nova memória é alocada para o novo valor e a alocação de memória anterior liberada. O System.StringBuilder foi projetado para ter o conceito de uma sequência mutável, na qual uma variedade de operações pode ser executada sem a alocação de um local de memória separado para a sequência modificada.
fonte
Outra solução:
dentro do loop, use List em vez de string.
é muito muito rápido.
fonte
Realmente depende do seu padrão de uso. Uma referência detalhada entre string.Join, string, Concat e string.Format pode ser encontrada aqui: String.Format não é adequado para registro intensivo
(Esta é realmente a mesma resposta que dei a esta pergunta)
fonte
Isso dependeria do código. O StringBuilder é mais eficiente em geral, mas se você estiver concatenando apenas algumas seqüências e fazendo tudo em uma linha, as otimizações de código provavelmente cuidarão disso para você. É importante pensar também na aparência do código: para conjuntos maiores, o StringBuilder facilitará a leitura, para conjuntos pequenos, o StringBuilder apenas adiciona desordem desnecessária.
fonte