Experimente este código.
É uma versão ligeiramente modificada do seu código.
1. Removai o Console.WriteLine, pois provavelmente há poucas ordens de magnitude mais lentas do que o que estou tentando medir.
2. Estou iniciando o cronômetro antes do loop e interrompendo-o logo depois, desta forma não perderei precisão se a função levar, por exemplo, 26,4 ticks para executar.
3. A maneira como você dividiu o resultado por algumas iterações estava errada. Veja o que acontece se você tiver 1000 milissegundos e 100 milissegundos. Nas duas situações, você receberá 0 ms depois de dividir por 1000000.
Stopwatch s = new Stopwatch();
var p = new { FirstName = "Bill", LastName = "Gates" };
int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;
string result;
s.Start();
for (var i = 0; i < n; i++)
result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();
Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);
Esses são os meus resultados:
1000000 x resultado = string.Format ("{0} {1}", p.FirstName, p.LastName); levou: 618ms - 2213706 ticks
1000000 x resultado = (p.PrimeiroNome + "" + p.ÚltimoNome); levou: 166ms - 595610 carrapatos
string.Format
que não usa nenhum recurso de formatação composta (isto é, simples{0}
) e substitui-os pela concatenação de cadeias consideravelmente mais rápida. Gostaria de saber que tal feito é possível com um reescritor de IL existente, como o PostSharp.Estou surpreso que tantas pessoas imediatamente desejem encontrar o código que executa o mais rápido. Se UM MILHÃO de iterações AINDA demorar menos de um segundo para processar, isso será de QUALQUER FORMA perceptível para o usuário final? Não muito provável.
Eu iria com a
String.Format
opção, apenas porque faz mais sentido do ponto de vista arquitetônico. Eu não me importo com o desempenho até que isso se torne um problema (e, caso isso acontecesse, eu me perguntaria: preciso concatenar um milhão de nomes de uma vez? Certamente nem todos caberão na tela ...)Considere se o seu cliente deseja alterá-lo posteriormente para que ele possa configurar se deseja exibir
"Firstname Lastname"
ou"Lastname, Firstname."
com a opção Formato, isso é fácil - basta trocar a string de formato. Com o concat, você precisará de código extra. Certamente isso não soa muito nesse exemplo em particular, mas extrapola.fonte
Oh, meu Deus - depois de ler uma das outras respostas, tentei reverter a ordem das operações - executando primeiro a concatenação e depois o String.Format ...
Portanto, a ordem das operações faz uma enorme diferença, ou melhor, a primeira operação é SEMPRE muito mais lenta.
Aqui estão os resultados de uma execução em que as operações são concluídas mais de uma vez. Tentei alterar as ordens, mas as coisas geralmente seguem as mesmas regras, uma vez que o primeiro resultado é ignorado:
Como você pode ver, as execuções subseqüentes do mesmo método (refatorei o código em três métodos) são incrementalmente mais rápidas. O mais rápido parece ser o método Console.WriteLine (String.Concat (...)), seguido pela concatenação normal e depois pelas operações formatadas.
O atraso inicial na inicialização provavelmente é a inicialização do Stream do console, como colocar um Console.Writeline ("Start!") Antes da primeira operação trazer todos os tempos de volta à linha.
fonte
As strings são imutáveis, isso significa que o mesmo pequeno pedaço de memória é usado repetidamente em seu código. Adicionar as mesmas duas seqüências e criar a mesma nova sequência repetidamente não afeta a memória. .Net é inteligente o suficiente apenas para usar a mesma referência de memória. Portanto, seu código não testa verdadeiramente a diferença entre os dois métodos concat.
Tente isso para obter o tamanho:
Saída de amostra:
fonte
string.Format
vale o pequeno desempenho atingido aqui. Arquitetonicamente, é melhor, pois significa que você pode alterar o formato mais facilmente. Mas construtor de cordas realmente não entendo o ponto. Todos os outros tópicos aqui dizem que você deve usar o Stringbuilder em vez de concatenar as strings. Qual a vantagem? Claramente, não velocidade, como este benchmark prova.Tenha pena dos pobres tradutores
Se você sabe que seu aplicativo permanecerá em inglês, tudo bem, salve o relógio. No entanto, muitas culturas costumam ver Sobrenome Nome em, por exemplo, endereços.
Portanto
string.Format()
, use , especialmente se você quiser que seu aplicativo vá para qualquer lugar em que o inglês não seja o primeiro idioma.fonte
string.Format()
comportaria diferente em diferentes culturas? Ainda não imprimiria o nome e o sobrenome? Parece que você teria que levar em conta a cultura diferente nas duas situações. Eu sinto que estou perdendo alguma coisa aqui.string.Format()
saberia que você estava usando um nome para um endereço? Sestring.Format()
trocado com{0} {1}
base na cultura, consideraria quebrado.Aqui estão meus resultados com mais de 100.000 iterações:
E aqui está o código do banco:
Então, eu não sei cuja resposta marcar como resposta :)
fonte
Concatenar seqüências de caracteres é bom em um cenário simples como esse - é mais complicado com algo mais complicado que isso, até Sobrenome, Nome. Com o formato, você pode ver, de relance, qual será a estrutura final da string ao ler o código; com concatenação, torna-se quase impossível discernir imediatamente o resultado final (exceto com um exemplo muito simples como este).
A longo prazo, o que isso significa é que, quando você voltar para fazer uma alteração no formato da sua string, poderá aparecer e fazer alguns ajustes na string de formatação ou enrugar a sobrancelha e começar a se mover tipos de acessadores de propriedades misturados com texto, com maior probabilidade de apresentar problemas.
Se você estiver usando o .NET 3.5, poderá usar um método de extensão como este e obter uma fluidez fácil, fora da sintaxe do manguito da seguinte maneira:
Por fim, à medida que seu aplicativo cresce em complexidade, você pode decidir que, para manter cordas em seu aplicativo, você deseja movê-las para um arquivo de recurso para localizar ou simplesmente para um auxiliar estático. Isso será MUITO mais fácil de obter se você tiver usado formatos consistentemente e seu código puder ser simplesmente refatorado para usar algo como
fonte
Para manipulação muito simples, eu usaria a concatenação, mas depois que você ultrapassa 2 ou 3 elementos, o Format torna-se IMO mais apropriado.
Outro motivo para preferir String.Format é que as seqüências .NET são imutáveis e, dessa maneira, cria menos cópias temporárias / intermediárias.
fonte
Embora eu compreenda totalmente a preferência de estilo e escolhi a concatenação para minha primeira resposta parcialmente com base em minha própria preferência, parte da minha decisão foi baseada no pensamento de que a concatenação seria mais rápida. Então, por curiosidade, eu testei e os resultados foram surpreendentes, especialmente para uma corda tão pequena.
Usando o seguinte código:
Eu obtive os seguintes resultados:
O uso do método de formatação é 100 vezes mais lento !! A concatenação nem se registrou como 1 ms, e é por isso que eu mostro os tiques do timer também.
fonte
A partir do C # 6.0, seqüências interpoladas podem ser usadas para fazer isso, o que simplifica ainda mais o formato.
As seqüências de caracteres interpoladas têm desempenho semelhante ao String.Format, mas melhoram a legibilidade e a sintaxe mais curta, devido ao fato de que valores e expressões são inseridos em linha.
Consulte também este artigo do dotnetperls sobre interpolação de strings.
Se você está procurando uma maneira padrão de formatar suas seqüências, isso faz sentido em termos de legibilidade e desempenho (exceto se microssegundos fará diferença no seu caso de uso específico).
fonte
Para concatenação básica de strings, geralmente uso o segundo estilo - mais fácil de ler e mais simples. No entanto, se estou fazendo uma combinação de strings mais complicada, geralmente opto por String.Format.
String.Format economiza em muitas citações e vantagens ...
Apenas alguns caracteres salvos, mas acho que, neste exemplo, o formato o torna muito mais limpo.
fonte
Um teste melhor seria observar sua memória usando o Perfmon e os contadores de memória CLR. Meu entendimento é que todo o motivo pelo qual você deseja usar String.Format, em vez de apenas concatenar cadeias, é que, como as cadeias são imutáveis, você está sobrecarregando desnecessariamente o coletor de lixo com cadeias temporárias que precisam ser recuperadas na próxima passagem.
StringBuilder e String.Format, embora potencialmente mais lentos, são mais eficientes em termos de memória.
O que há de tão ruim na concatenação de strings?
fonte
Geralmente eu prefiro o primeiro, pois especialmente quando as cordas ficam longas, pode ser muito mais fácil de ler.
O outro benefício é que acredito que seja o desempenho, pois ele efetivamente executa duas instruções de criação de sequência antes de passar a sequência final para o método Console.Write. String.Format usa um StringBuilder sob as capas, acredito, para evitar várias concatenações.
Deve-se notar, no entanto, que se os parâmetros que você está transmitindo para String.Format (e outros métodos como o Console.Write) são tipos de valor, eles serão colocados em caixas antes da transmissão, o que pode fornecer seus próprios resultados de desempenho. Postagem de blog sobre isso aqui .
fonte
Daqui a uma semana, a partir de 19 de agosto de 2015, esta pergunta terá exatamente sete (7) anos. Agora existe uma maneira melhor de fazer isso. Melhor em termos de manutenção, pois não realizei nenhum teste de desempenho em comparação com apenas concatenar seqüências de caracteres (mas isso importa hoje em dia? Alguns milissegundos de diferença?). A nova maneira de fazer isso com o C # 6.0 :
Esse novo recurso é melhor , IMO e, na verdade, melhor no nosso caso, pois temos códigos nos quais construímos cadeias de consulta cujos valores dependem de alguns fatores. Imagine uma querystring em que temos 6 argumentos. Então, em vez de fazer um, por exemplo:
in pode ser escrito assim e é mais fácil ler:
fonte
fonte
Eu escolho com base na legibilidade. Eu prefiro a opção de formato quando há algum texto em torno das variáveis. Neste exemplo:
você entende o significado mesmo sem nomes de variáveis, enquanto o concat está cheio de aspas e sinais de + e confunde meus olhos:
(Emprestei o exemplo de Mike porque eu gosto)
Se a string de formato não significa muito sem nomes de variáveis, tenho que usar concat:
A opção de formato me faz ler os nomes das variáveis e mapeá-los para os números correspondentes. A opção concat não exige isso. Ainda estou confuso com as aspas e os sinais +, mas a alternativa é pior. Rubi?
Em termos de desempenho, espero que a opção de formato seja mais lenta que a concat, pois o formato requer que a string seja analisada . Não me lembro de ter que otimizar esse tipo de instrução, mas, se o fizesse, examinaria
string
métodos comoConcat()
eJoin()
.A outra vantagem do formato é que a string de formato pode ser colocada em um arquivo de configuração. Muito útil com mensagens de erro e texto da interface do usuário.
fonte
Eu usaria o String.Format, mas também teria a string de formato nos arquivos de recursos para que ela possa ser localizada em outros idiomas. O uso de uma simples concat de strings não permite que você faça isso. Obviamente, se você nunca precisar localizar essa string, esse não é um motivo para pensar. Realmente depende do objetivo da string.
Se ele for mostrado ao usuário, eu usaria String.Format para localizar se precisar - e o FxCop fará a verificação ortográfica para mim, apenas no caso :)
Se ele contiver números ou qualquer outra coisa que não seja uma string (por exemplo, datas), eu usaria String.Format porque isso me dá mais controle sobre a formatação .
Se for para criar uma consulta como SQL, eu usaria o Linq .
Se para concatenar seqüências de caracteres dentro de um loop, eu usaria o StringBuilder para evitar problemas de desempenho.
Se for para alguma saída, o usuário não verá, e não afetará o desempenho, eu usaria String.Format porque tenho o hábito de usá-lo de qualquer maneira e estou acostumado a isso :)
fonte
Se você está lidando com algo que precisa ser fácil de ler (e isso é mais código), eu continuaria com a versão de sobrecarga do operador, A menos que:
Sob pelo menos duas dessas circunstâncias, eu usaria o StringBuilder.
fonte
Se você deseja localizar o resultado, String.Format é essencial porque diferentes idiomas naturais podem até não ter os dados na mesma ordem.
fonte
Eu acho que isso depende muito de quão complexa é a saída. Costumo escolher o cenário que melhor funciona no momento.
Escolha a ferramenta certa com base no trabalho: D O que parecer mais limpo!
fonte
Prefiro o segundo também, mas não tenho argumentos racionais no momento para apoiar essa posição.
fonte
Agradável!
Acabei de adicionar
E é ainda mais rápido (acho que string.Concat é chamado nos dois exemplos, mas o primeiro requer algum tipo de tradução).
fonte
string.Concat(...)
. Isso é feito durante a compilação, portanto, não afeta o desempenho em tempo de execução. Se você executar seus testes várias vezes ou executá-los em uma amostra maior, verá que eles são idênticos.Como não acho que as respostas aqui abranjam tudo, gostaria de fazer uma pequena adição aqui.
Console.WriteLine(string format, params object[] pars)
chamadasstring.Format
. O '+' implica concatenação de string. Eu não acho que isso sempre tenha a ver com estilo; Eu costumo misturar os dois estilos, dependendo do contexto em que estou.Resposta curta
A decisão que você está enfrentando tem a ver com a alocação de string. Vou tentar simplificar.
Diga que você tem
Se você executar isso, ele avaliará da seguinte maneira:
tmp
aqui não é realmente uma variável local, mas é temporária para o JIT (é empurrada na pilha IL). Se você pressionar uma string na pilha (comoldstr
em IL para literais), você colocará uma referência a um ponteiro de string na pilha.O momento em que você chama
concat
essa referência se torna um problema, porque não há nenhuma referência de string disponível que contenha as duas strings. Isso significa que o .NET precisa alocar um novo bloco de memória e preenchê-lo com as duas seqüências de caracteres. A razão pela qual isso é um problema é porque a alocação é relativamente cara.O que muda a pergunta para: Como você pode reduzir o número de
concat
operações?Portanto, a resposta aproximada é:
string.Format
para> 1 concats, '+' funcionará bem para 1 concat. E se você não se importa em fazer otimizações de micro-desempenho,string.Format
funcionará bem no caso geral.Uma nota sobre Cultura
E depois há algo chamado cultura ...
string.Format
permite usarCultureInfo
na sua formatação. Um operador simples '+' usa a cultura atual.Esta é uma observação especialmente importante se você estiver escrevendo formatos de arquivo e f.ex.
double
valores que você 'adiciona' a uma sequência. Em máquinas diferentes, você pode acabar com cadeias diferentes se não usarstring.Format
com um explícitoCultureInfo
.F.ex. considere o que acontece se você alterar um '.' para um ',' enquanto escreve seu arquivo de valores separados por vírgula ... em holandês, o separador decimal é uma vírgula; portanto, o usuário pode ter uma surpresa 'engraçada'.
Resposta mais detalhada
Se você não souber o tamanho exato da string de antemão, é melhor usar uma política como essa para generalizar os buffers que você usa. O espaço livre é preenchido primeiro, após o qual os dados são copiados.
Crescer significa alocar um novo bloco de memória e copiar os dados antigos para o novo buffer. O antigo bloco de memória pode ser liberado. Você obtém os resultados neste ponto: crescer é uma operação cara.
A maneira mais prática de fazer isso é usar uma política de alocação geral. A política mais comum é alocar buffers em potências de 2. É claro que você precisa fazê-lo um pouco mais inteligente do que isso (já que não faz sentido aumentar de 1,2,4,8 se você já sabe que precisa de 128 caracteres ) mas você entendeu. A política garante que você não precise de muitas das operações caras que descrevi acima.
StringBuilder
é uma classe que basicamente aloca o buffer subjacente em potências de dois.string.Format
usaStringBuilder
sob o capô.Isso faz da sua decisão uma troca básica entre atribuir globalmente e acrescentar (múltiplos) (com duas culturas) ou apenas alocar e acrescentar.
fonte
Pessoalmente, o segundo como tudo o que você está usando está na ordem direta em que será emitido. Considerando que com o primeiro você precisa combinar o {0} e o {1} com o var apropriado, o que é fácil de bagunçar.
Pelo menos não é tão ruim quanto o sprintf C ++, onde se você errar o tipo de variável, tudo explodirá.
Além disso, como o segundo está todo em linha e não precisa pesquisar e substituir todas as coisas {0}, o último deve ser mais rápido ... embora eu não tenha certeza.
fonte
Na verdade, gosto da primeira, porque quando há muitas variáveis misturadas com o texto, parece mais fácil ler para mim. Além disso, é mais fácil lidar com aspas ao usar o formato string.Format (), uh. Aqui está uma análise decente da concatenação de strings.
fonte
Eu sempre fui a rota string.Format (). Ser capaz de armazenar formatos em variáveis como o exemplo de Nathan é uma grande vantagem. Em alguns casos, posso anexar uma variável, mas mais de uma variável está sendo concatenada, refatoro para usar a formatação.
fonte
Ah, e apenas para completar, a seguir estão alguns ticks mais rápidos que a concatenação normal:
fonte
O primeiro (formato) parece melhor para mim. É mais legível e você não está criando objetos de string temporários extras.
fonte
Fiquei curioso para saber onde StringBuilder estava com esses testes. Resultados abaixo ...
Resultados:
fonte
De acordo com o material de preparação do MCSD, a Microsoft sugere o uso do operador + ao lidar com um número muito pequeno de concatenações (provavelmente 2 a 4). Ainda não sei por que, mas é algo a considerar.
fonte