2012-08-13 10 views
5

que tienen un objeto StringBuilder donde yo estoy añadiendo algunas cadenas como sigue:¿Desempeño de StringBuilder en C#?

Quiero saber cuál es el mejor enfoque aquí, primero es la siguiente:

StringBuilder sb = new StringBuilder(); 
sb.Append("Hello" + "How" + "are" + "you"); 

y la segunda es:

StringBuilder sb = new StringBuilder(); 
sb.Append("Hello").Append("How").Append("are").Append("you"); 
+3

Consulte http://stackoverflow.com/questions/9132338/how-many-string-objects-will-be-created-when-using-a-plus-sign/9132374#9132374. Esto ha sido cubierto * a muerte * :-) –

+0

Puede encontrar [este análisis] (http://www.dotnetperls.com/stringbuilder-performance) interesante – Steve

+0

Mi pregunta es: ¿por qué querría hacer "Hola" + "Cómo", etc., cuando "HelloHow" estaría bien? ¿Cuál es el verdadero punto de la pregunta porque mi respuesta fue criticada por razones técnicas que no creo que sea el punto aquí? – Charleh

Respuesta

6

El primero será más eficiente. El compilador lo convertirá a la siguiente llamada individual:

StringBuilder sb = new StringBuilder(); 
sb.Append("HelloHowareyou"); 

Medir el desempeño

La mejor manera de saber que es más rápido es para medirlo. Voy a ir directo al punto: aquí están los resultados (tiempos más pequeño significa más rápido):

sb.Append("Hello" + "How" + "are" + "you")     : 11.428s 
sb.Append("Hello").Append("How").Append("are").Append("you"): 15.314s 
sb.Append(a + b + c + d)         : 21.970s 
sb.Append(a).Append(b).Append(c).Append(d)     : 15.529s 

El número dado es el número de segundos para realizar la operación de 100 millones de veces en un bucle estrecho.

Conclusiones

  • el más rápido está utilizando literales de cadena y +.
  • Pero si tiene variables, usar Append es más rápido que +. La primera versión es más lenta debido a una llamada adicional al String.Concat.

En caso de que quiera probar esto por sí mismo, aquí está el programa que utiliza para obtener los tiempos anteriores:

using System; 
using System.Text; 

public class Program 
{ 
    public static void Main() 
    { 
     DateTime start, end; 
     int numberOfIterations = 100000000; 
     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("Hello" + "How" + "are" + "you"); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(\"Hello\" + \"How\" + \"are\" + \"you\")", start, end); 

     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append("Hello").Append("How").Append("are").Append("you"); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(\"Hello\").Append(\"How\").Append(\"are\").Append(\"you\")", start, end); 

     string a = "Hello"; 
     string b = "How"; 
     string c = "are"; 
     string d = "you"; 

     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append(a + b + c + d); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(a + b + c + d)", start, end); 

     start = DateTime.UtcNow; 
     for (int i = 0; i < numberOfIterations; ++i) 
     { 
      StringBuilder sb = new StringBuilder(); 
      sb.Append(a).Append(b).Append(c).Append(d); 
     } 
     end = DateTime.UtcNow; 
     DisplayResult("sb.Append(a).Append(b).Append(c).Append(d)", start, end); 

     Console.ReadLine(); 
    } 

    private static void DisplayResult(string name, DateTime start, DateTime end) 
    { 
     Console.WriteLine("{0,-60}: {1,6:0.000}s", name, (end - start).TotalSeconds); 
    } 
} 
10

En el ejemplo actual, los literales de cadena:

"Hello" + "How" + "are" + "you" 

Se compilará en una cadena constante literal por el compilador, por lo que es técnicamente más rápido que:

sb.Append("Hello").Append("How").Append("are").Append("you"); 

Sin embargo, se le permite utilizar las variables de cadena:

sb.Append(s1 + s2 + s3 + s4); 

A continuación, este último sería más rápido que el primero podría potencialmente crear una serie de cuerdas (debido a la concatenación) antes pasar a la final en el método Append, mientras que el último evitaría las creaciones de cadenas adicionales (pero cambia las llamadas a métodos adicionales y el cambio de tamaño del búfer interno).

Actualización: Para mayor claridad, en esta situación exacta en la que sólo hay 4 elementos que son concatenados, el compilador emitirá una llamada a String.Concat(string, string, string, string), que sabiendo la longitud y el número de cuerdas será más eficiente que StringBuilder.

+0

Sí, obtendría 3 cadenas creadas en la evaluación de la expresión 's1 + s2 + s3 + s4': s1 + s2 -> t1, t1 + s3 -> t2, t2 + s2 -> t3. –

+0

@NicholasCarey no, en la evaluación de 's1 + s2 + s3 + s4', la única cadena nueva creada es el resultado. Esa expresión se compila en una sola llamada a 'String.Concat', que no asigna ninguna cadena adicional intermedia. –

+0

En este caso, como se deduce de las otras respuestas, 'String.Concat' puede terminar siendo más rápido (debido al redimensionamiento interno realizado por' StringBuilder'. En una instancia única como esta con cantidades conocidas, yo preferiría la concatenación Con cantidades desconocidas, como bucles, yo preferiría 'StringBuilder'. –

0

En el primer caso, el compilador construirá una sola cadena, por lo que solo llamará a Append una vez. Sin embargo, dudo que esto suponga una gran diferencia. ¿Qué mostraron tus medidas?

-5

El segundo es el mejor enfoque. Las cadenas son inmutables, lo que significa que cuando utiliza sb.Append ("Hola" + "Cómo" + "Son" + "Usted") está creando copias múltiples de la cadena

p.

"Hello" 

continuación

"HelloHow" 

continuación

"HelloHowAre" 

etc.

La segunda pieza de código es mucho más performante

edición: Por supuesto, esto no lo hace tomar en consideración Mejoras en el compilador de eración, pero es mejor usar la clase como se pretendía

Ok, como la gente ha señalado ya que estos son literales, el compilador se encarga de optimizar estas operaciones, pero mi punto es que la concatenación de cadenas es algo que StringBuilder intenta para evitar

Por ejemplo, un bucle varias veces como tal:

var someString = ""; 

foreach (var s in someListOfStrings) 
{ 
    someString += s; 
} 

no es tan bueno como hacerlo:

var sb = new StringBuilder(); 

foreach(var s in someListOfStrings) 
{ 
    sb.Append(s); 
} 

sb.ToString(); 

Como esto probablemente será mucho más rápido, ya que, como he dicho antes, las cadenas son inmutables

asumí el PO estaba hablando acerca del uso de la concatenación en general desde

sb.Append("Hello" + "How"); 

parece completamente inútil cuando

sb.Append("HelloHow"); 

¿Sería más lógico ...?

Me parece que en la mente PO, el texto del marcador de posición con el tiempo se convertiría en una de las variables shedload ...

+1

En realidad, no está haciendo esto, el compilador lo asigna a una sola llamada String.Concat. –

+1

' "Hello" + "How" + "Are" + "Usted" 'son 'literales' de cadena aunque – dtsg

+0

@john no después de que el compilador los haya completado. Si el código está escrito de esa manera, el compilador los pliega en un solo literal de cadena. –

4

Las constantes de cadena se concatenan en tiempo de compilación por el compilador. Si está concatenando no más de cuatro expresiones de cadena, el compilador emitirá una llamada a String.Concat

s + t + u + v ==> String.Concat(s, t, u, v) 

Esto realiza más rápido que StringBuilder, como StringBuilder podría tener que cambiar el tamaño de su buffer interno, mientras Concat puede calcular la longitud total resultante por adelantado.Si conoce la longitud máxima de la cadena resultante de antemano, sin embargo, se puede inicializar el StringBuilder especificando un tamaño de búfer de trabajo inicial

var sb = new StringBuilder(initialBufferSize); 

StringBuilder se utiliza a menudo en un bucle y otros escenarios dinámicos y realiza más rápido que s += t en esos casos.

+0

+1 para la información de Concat. –