Cadena vs StringBuilder


Entiendo la diferencia entre String y StringBuilder (StringBuilder ser mutable), pero hay una gran diferencia de rendimiento entre los dos?

El programa en el que estoy trabajando tiene una gran cantidad de adjuntos de cadenas de caracteres impulsados por mayúsculas y minúsculas (más de 500). ¿Usar StringBuilder es una mejor opción?

Author: Peter Mortensen, 2008-09-16

24 answers

Sí, la diferencia de rendimiento es significativa. Consulte el artículo de KB " Cómo mejorar el rendimiento de la concatenación de cadenas en Visual C#".

Siempre he intentado codificar primero para mayor claridad y luego optimizar el rendimiento más tarde. ¡Eso es mucho más fácil que hacerlo al revés! Sin embargo, después de haber visto la enorme diferencia de rendimiento en mis aplicaciones entre los dos, ahora lo pienso un poco más cuidadosamente.

Afortunadamente, es relativamente sencillo para ejecutar análisis de rendimiento en su código para ver dónde está gastando el tiempo, y luego modificarlo para usar StringBuilder donde sea necesario.

 213
Author: Jay Bazuzi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-12 19:16:12

Para aclarar lo que Gillian dijo sobre 4 cuerdas, si tienes algo como esto:

string a,b,c,d;
 a = b + c + d;

Entonces sería más rápido usando cadenas y el operador plus. Esto se debe a que (como Java, como señala Eric), utiliza internamente StringBuilder automáticamente (En realidad, utiliza una primitiva que StringBuilder también usa)

Sin embargo, si lo que estás haciendo está más cerca de:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

Entonces necesitas usar explícitamente un StringBuilder. . Net no crea automáticamente un StringBuilder aquí, porque no tendría sentido. Al final de cada línea, "a" tiene que ser una cadena (inmutable), por lo que tendría que crear y disponer de un StringBuilder en cada línea. Para la velocidad, necesitas usar el mismo StringBuilder hasta que termines de construir:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();
 51
Author: James Curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 16:18:10

StringBuilder es preferible SI está haciendo múltiples bucles o bifurcaciones en su pase de código... sin embargo, para el rendimiento PURO, si puede salirse con la suya con una declaración de cadena SIMPLE, entonces eso es mucho más performante.

Por ejemplo:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

Es más eficiente 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..

En este caso, StringBuild podría considerarse más mantenible, pero no es más performante que la declaración de una sola cadena.

9 veces de 10 sin embargo... utilizar el constructor de cuerdas.

En una nota al margen: string + var también es más performante que la string.Enfoque de formato (generalmente) que usa un StringBuilder internamente (en caso de duda... compruebe el reflector!)

 28
Author: calebjenkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 17:48:14

Este punto de referencia muestra que la concatenación regular es más rápida cuando se combinan 3 cadenas o menos.

Http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster /

StringBuilder puede hacer una mejora muy significativa en el uso de memoria, especialmente en su caso de agregar 500 cadenas juntas.

Considere el siguiente ejemplo:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

¿Qué sucede en la memoria? Se crean las siguientes cadenas:

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"

Sumando esos cinco números al final de la cadena hemos creado 13 objetos de cadena! Y 12 de ellos fueron inútiles! ¡Órale!

StringBuilder soluciona este problema. No es una" cadena mutable " como a menudo escuchamos (todas las cadenas en.NET son inmutables). Funciona manteniendo un búfer interno, una matriz de caracteres. Llamando a Append() o AppendLine () añade la cadena al espacio vacío al final del array char; si el array es demasiado pequeño, crea un nuevo array más grande, y copia el búfer allí. Así que en el ejemplo arriba, StringBuilder solo podría necesitar una sola matriz para contener las 5 adiciones a la cadena depending dependiendo del tamaño de su búfer. Puedes decirle a StringBuilder qué tan grande debe ser su búfer en el constructor.

 22
Author: Matt Trunnell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 16:27:08

Un ejemplo sencillo para demostrar la diferencia de velocidad al usar String contactenation 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 contactenation: " + time.ElapsedMilliseconds + " milliseconds");

Resultado:

Usando la contactenación de cadenas: 15423 milisegundos

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 milisegundos

Como resultado, la primera iteración tomó 15423 ms, mientras que la segunda iteración usando StringBuilder tomó 10 ms.

Me parece que usar StringBuilder es más rápido, mucho más rápido.

 18
Author: Diizzy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 16:46:04

No vayas ciegamente por StringBuilder. Hay escenarios en los que StringBuilder no mejora el rendimiento.

Rico Mariani ha escrito dos entradas de blog perspicaces sobre esto:

Http://blogs.msdn.com/ricom/archive/2003/12/02/40778.aspx

Http://blogs.msdn.com/ricom/archive/2003/12/15/43628.aspx

 14
Author: Nimesh Madhavan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-01 15:01:23

Sí, StringBuilder proporciona un mejor rendimiento al realizar operaciones repetidas sobre una cadena. Se debe a que todos los cambios se realizan en una sola instancia para que pueda ahorrar mucho tiempo en lugar de crear una nueva instancia como String.

String Vs Stringbuilder

  • String

    1. bajo System espacio de nombres
    2. instancia inmutable (de solo lectura)
    3. el rendimiento se degrada cuando ocurre un cambio continuo de valor
    4. hilo safe
  • StringBuilder (cadena mutable)

    1. bajo System.Text espacio de nombres
    2. instancia mutable
    3. muestra un mejor rendimiento ya que se realizan nuevos cambios en la instancia existente

Recomiendo encarecidamente el artículo de dotnet mob : String Vs StringBuilder en C#.

Pregunta relacionada con el desbordamiento de pila: Mutabilidad de la cadena cuando la cadena no cambia en C#?.

 10
Author: Shamseer K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-12 03:32:03

StringBuilder reduce el número de asignaciones y asignaciones, a un costo de memoria extra utilizada. Si se usa correctamente, puede eliminar por completo la necesidad de que el compilador asigne cadenas más y más grandes una y otra vez hasta que se encuentre el resultado.

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
 8
Author: moswald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 18:43:06

El rendimiento de una operación de concatenación para un objeto String o StringBuilder depende de la frecuencia con la que se produce una asignación de memoria. Una operación de concatenación de cadenas siempre asigna memoria, mientras que una operación de concatenación de StringBuilder solo asigna memoria si el búfer de objetos StringBuilder es demasiado pequeño para acomodar los nuevos datos. En consecuencia, la clase String es preferible para una operación de concatenación si se concatenan un número fijo de objetos String. En ese caso, el las operaciones de concatenación individuales pueden incluso ser combinadas en una sola operación por el compilador. Un objeto StringBuilder es preferible para una operación de concatenación si se concatenan un número arbitrario de cadenas; por ejemplo, si un bucle concatena un número aleatorio de cadenas de entrada del usuario.

Fuente: MSDN

 4
Author: user487069,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-11 21:06:16

StringBuilder es mejor para construir una cadena a partir de muchos valores no constantes.

Si está construyendo una cadena a partir de muchos valores constantes, como múltiples líneas de valores en un documento HTML o XML u otros trozos de texto, puede salirse con la suya simplemente añadiendo a la misma cadena, porque casi todos los compiladores hacen "plegado constante", un proceso de reducción del árbol de análisis cuando tiene un montón de manipulación constante (también se usa cuando escribe algo como int minutesPerYear = 24 * 365 * 60). Y por simple casos con valores no constantes anexados entre sí, el compilador.NET reducirá su código a algo similar a lo que hace StringBuilder.

Pero cuando tu append no puede ser reducido a algo más simple por el compilador, querrás un StringBuilder. Como señala Fizch, es más probable que ocurra dentro de un bucle.

 3
Author: JasonTrue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 17:12:02

Creo que StringBuilder es más rápido si tiene más de 4 cadenas que necesita agregar juntas. Además, puede hacer algunas cosas geniales como AppendLine.

 2
Author: Gilligan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 15:59:17

En.NET, StringBuilder sigue siendo más rápido que añadir cadenas. Estoy bastante seguro de que en Java, simplemente crean un StringBuffer debajo del capó cuando anexas cadenas, por lo que no hay realmente una diferencia. No estoy seguro de por qué no han hecho esto en.NET todavía.

 2
Author: Eric Z Beard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 15:59:40
 2
Author: Jim G.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-18 15:03:50

El uso de cadenas para la concatenación puede llevar a una complejidad de tiempo de ejecución del orden de O(n^2).

Si usa un StringBuilder, hay mucho menos copiado de memoria que se debe hacer. Con el StringBuilder(int capacity) puede aumentar el rendimiento si puede estimar cuán grande será el String final. Incluso si no eres preciso, probablemente solo tendrás que aumentar la capacidad de StringBuilder un par de veces, lo que también puede ayudar al rendimiento.

 2
Author: Steve g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 17:13:29

He visto ganancias significativas de rendimiento al usar el método EnsureCapacity(int capacity) llamar a una instancia de StringBuilder antes de usarlo para cualquier almacenamiento de cadenas. Normalmente lo llamo en la línea de código después de la instanciación. Tiene el mismo efecto que si instanciaras el StringBuilder de esta manera:

var sb = new StringBuilder(int capacity);

Esta llamada asigna la memoria necesaria antes de tiempo, lo que causa menos asignaciones de memoria durante múltiples operaciones Append(). Usted tiene que hacer una suposición educada sobre la cantidad de memoria que necesitará, pero para la mayoría aplicaciones esto no debería ser demasiado difícil. Me suelen equivocarse en el lado de un poco de demasiada memoria (estamos hablando de 1k o así).

 2
Author: Jason Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 17:20:02

Además de las respuestas anteriores, lo primero que siempre hago cuando pienso en temas como este es crear una pequeña aplicación de prueba. Dentro de esta aplicación, realizar alguna prueba de tiempo para ambos escenarios y ver por sí mismo que es más rápido.

En mi humilde opinión, agregar más de 500 entradas de cadena definitivamente debería usar StringBuilder.

 1
Author: RichS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 16:02:55

String y StringBuilder son en realidad ambos inmutables, el StringBuilder ha construido búferes que permiten que su tamaño se administre de manera más eficiente. Cuando el StringBuilder necesita redimensionarse es cuando se re-asigna en el montón. Por defecto tiene un tamaño de 16 caracteres, puede configurarlo en el constructor.

Eg.

StringBuilder sb = new StringBuilder (50);

 1
Author: capgpilk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 16:13:14

La concatenación de cadenas le costará más. En Java, puede usar StringBuffer o StringBuilder según sus necesidades. Si desea una implementación sincronizada y segura de subprocesos, vaya a StringBuffer. Esto será más rápido que la concatenación de cadenas.

Si no necesita una implementación sincronizada o segura de subprocesos, vaya a StringBuilder. Esto será más rápido que la concatenación de cadenas y también más rápido que StringBuffer, ya que no hay sobrecarga de sincronización.

 1
Author: raffimd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 18:09:59

StringBuilder es probablemente preferible. La razón es que asigna más espacio del que se necesita actualmente (se establece el número de caracteres) para dejar espacio para futuros anexos. Entonces esos anexos futuros que caben en el búfer actual no requieren ninguna asignación de memoria o recolección de basura, lo que puede ser costoso. En general, uso StringBuilder para concatentación de cadenas complejas o formato múltiple, luego convierto a una cadena normal cuando los datos están completos, y quiero una cadena inmutable objeto de nuevo.

 0
Author: deemer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 16:01:09

Si está haciendo una gran cantidad de concatenación de cadenas, use un constructor de cadenas. Cuando concatena con una cadena, crea una nueva cada vez, utilizando más memoria.

Alex

 0
Author: Alex Fort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 16:01:17

Como regla general, si tengo que establecer el valor de la cadena más de una vez, o si hay algún apéndice a la cadena, entonces necesita ser un constructor de cadenas. He visto aplicaciones que he escrito en el pasado antes de aprender sobre los constructores de cadenas que han tenido una gran huella de memoria que parece seguir creciendo y creciendo. Cambiar estos programas para usar el constructor de cadenas reduce significativamente el uso de memoria. Ahora lo juro por el constructor de cuerdas.

 0
Author: user13288,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-01 15:00:17

Mi enfoque siempre ha sido usar StringBuilder al concatenar 4 o más cadenas O Cuando no se como pueden ocurrir las concatenaciones.

Buen rendimiento artículo relacionado aquí

 0
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-01 15:02:39

StringBuilder es significativamente más eficiente, pero no verá ese rendimiento a menos que esté haciendo una gran cantidad de modificación de cadenas.

A continuación se muestra un fragmento rápido de código para dar un ejemplo del rendimiento. Como puedes ver, realmente solo empiezas a ver un aumento importante del rendimiento cuando te metes en iteraciones grandes.

Como puedes ver, las 200.000 iteraciones tardaron 22 segundos, mientras que las 1 millones de iteraciones que usaban StringBuilder fueron casi 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 de la código anterior:

Cadena inicial + al 28/01/2013 16:55:40.

Cadena terminada + en 28/01/2013 16:55:40.

Cadena inicial + al 28/01/2013 16:55:40.

Cadena terminada + en 28/01/2013 16:56:02.

A partir de Sb append en 28/01/2013 16:56:02.

Terminado Sb append en 28/01/2013 16:56:02.

 0
Author: CathalMF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 17:05:06

StringBuilder funcionará mejor, desde un punto de soporte de memoria. En cuanto al procesamiento, la diferencia en el tiempo de ejecución puede ser insignificante.

 -2
Author: DevelopingChris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 15:57:51