2009-10-23 29 views
16

Tengo una situación en la que necesito concatenar varias cadenas para formar una identificación de una clase. Básicamente estoy haciendo un bucle en una lista para obtener los valores ToString de los objetos y luego concatenarlos.Cadena de concatenación vs String Builder. Rendimiento

foreach (MyObject o in myList) 
    result += o.ToString(); 

la lista no se espera que tenga más de 5 elementos (aunque podría pero eso es un caso muy, muy marginal) y por lo general va a tener de 1 a 3 elementos, siendo común a que sólo tienen uno o dos.

¿Cuál sería el rendimiento, la concatenación o el uso de un StringBuilder?

StringBuilder bld = new StringBuilder() 
foreach (MyObject o in myList) 
    bld.Append(o.ToString()); 

estoy seguro si la creación de la StringBuilder tomará más tiempo que la concatenación estándar para el caso más habitual.

Esto es flojo, los elementos de la lista no cambian una vez creados, por lo que la identificación se construye perezosamente una vez cuando se llama.

Como nota al margen ... ¿Debo usar una matriz fija en lugar de una lista? ¿Obtendré algún rendimiento o mejora de la memoria si lo hago? (La lista solo se usa como un IEnumerable de todos modos)

Una vista más general de la pregunta podría ser, ¿cuántas cadenas son suficientes para detener la concatenación y comenzar a construir?

¿Debo molestarme en probar el caso?

if (myList.Count > 4) 
    ConcatWithStringBuilder(myList); 
+0

Este sería el caso perfecto para una micro-optimización inane. Ni siquiera te molestes con esta cantidad de cuerdas. –

+1

¿La diferencia de microsegundos en el tiempo vale la pena? El tiempo que tardó en escribir esta pregunta es probablemente más que la diferencia entre concat/builder durante la vida del programa. Especialmente si es flojo y solo se llama una vez por ejecución. –

+0

Posible duplicado de [String vs. StringBuilder] (https://stackoverflow.com/questions/73883/string-vs-stringbuilder) – Matt

Respuesta

23

La respuesta habitual es que la concatenación de cadenas es más eficiente para entre 4 y 8 cadenas. Depende de qué blog lees.

No escriba una prueba para decidir qué método usar. Si no está seguro de si rebasará el límite mágico, simplemente use StringBuilder.

Ejecutar este código para ver los resultados por ti mismo:

const int sLen=30, Loops=5000; 
DateTime sTime, eTime; 
int i; 
string sSource = new String('X', sLen); 
string sDest = ""; 
// 
// Time string concatenation. 
// 
sTime = DateTime.Now; 
for(i=0;i<Loops;i++) sDest += sSource; 
eTime = DateTime.Now; 
Console.WriteLine("Concatenation took " + (eTime - sTime).TotalSeconds + " seconds."); 
// 
// Time StringBuilder. 
// 
sTime = DateTime.Now; 
System.Text.StringBuilder sb = new System.Text.StringBuilder((int)(sLen * Loops * 1.1)); 
for(i=0;i<Loops;i++) sb.Append(sSource); 
sDest = sb.ToString(); 
eTime = DateTime.Now; 
Console.WriteLine("String Builder took " + (eTime - sTime).TotalSeconds + " seconds."); 
// 
// Make the console window stay open 
// so that you can see the results when running from the IDE. 
// 
Console.WriteLine(); 
Console.Write("Press Enter to finish ... "); 
Console.Read(); 

Ref. http://support.microsoft.com/kb/306822

+1

Creo que hay confusión sobre este tema y depende de quién es la opinión que respetas. El resultado final, por lo que entiendo es que las diferencias en el rendimiento solo son realmente evidentes cuando el código se golpea con frecuencia y bajo una carga significativa. –

+0

@Aliixx: estoy completamente de acuerdo. –

+0

@Foxfire: Bien, digamos "un artículo que presenta un par de vistas diferentes sobre cuál es el número mágico de concatenaciones para hacer la elección entre cadena y StringBuilder" –

0

El constructor de cadena muy probable que sea ligeramente más rápido en este caso, pero en realidad es probable que no va a ser suficiente para preocuparse. Realmente va a depender de dos cosas, la cantidad de veces que está recreando la cadena (porque las cadenas son inmutables y la unión obliga a crear una nueva cadena a partir de las dos existentes), y el tamaño de los elementos de cadena que se concatenan juntos. Concatenar cinco cadenas de 2 bytes cada una va a ser muy diferente de concatenar 5 cadenas juntas que son 5000 bytes cada una, porque cuanto más larga es la cadena, más trabajo debe hacer el sistema para asignar memoria y recoger objetos que no son basura. más tiempo en uso. El generador de cadenas es una mejor apuesta, porque ya se ha optimizado para unir cadenas, y realmente no tienes que preocuparte por consideraciones de rendimiento.

Teniendo todo esto en cuenta, si conoce el tamaño final de la cadena, el creador de cadenas será casi seguro más rápido. Cuando le diga cuánta memoria asignar para la cadena final, no tendrá que pasar por el proceso de reasignar la memoria.

0

Si puede estimar el número de bytes que se utilizarán para la cadena completa (y usar esto para inicializar la capacidad de StringBuilder), es probable que StringBuilder supere a la clase String al hacer más de aproximadamente 3 concatetos.

11

Apoyo la idea de mantener las cosas simples hasta que tenga una buena razón para hacerlas complejas.

Para algo así como 2-5 elementos no tiene sentido utilizar StringBuilder (a menos que repita esta concatenación continuamente). La sintaxis mejor legible "+ =" tiene más valor.

+0

¿Debo molestarme en probar el caso? –

+2

Si tiene curiosidad, ¿por qué no? –

+0

No, quise decir como prueba si el número de objetos en la lista es mayor que X do StringBuilder, oc do concat. He actualizado el cuerpo de la pregunta con esto :) –

0

Usaría StringBuilder solo porque desea ser coherente en toda la aplicación. La instanciación de un objeto Java/.NET tampoco consume mucho tiempo, aunque supongo que habrá algún servicio de limpieza en la configuración de StringBuilder.No es mucho peor que crear múltiples objetos String a través de la concatenación seguramente.

3

Una vista más general de la pregunta podría ser, ¿cuántas cadenas son suficientes para detener la concatenación y comenzar a construir?

Esto depende de la longitud de las cuerdas y si se puede predecir la longitud de destino entonces usted debe suministrar la longitud de la StringBuilder constructor y si todos ellos concatenar a la vez o dentro de varios pasos.

Si los concatena a la vez (como s = "A" + "b" + "c" + "d") a continuación, utilizando StringBuilder probable es que nunca tiene sentido.

Si puede predecir exactamente la longitud, incluso para 3 cadenas, StringBuilder sería más rápido.

Por lo general, StringBuilder es más rápido si tienes más de 5 concatts. Pero incluso entonces simplemente concatenar las cuerdas generalmente tiene poca sobrecarga (a menos que se ejecute en un bucle cerrado).

Tan pronto como llegue a 10 concats usando StringBuilder probablemente será favorable.

Editar: Para que quede claro: En su caso, claramente debe ir sin StringBuilder.

1

Concatenación de cadenas IMO es más legible. Utiliza + y + = en lugar de strBldInstance.Add() que puede enturbiar el código un poco más,

StringBuilder existe para hacer que la concatenación sea más eficiente, mucho más, pero generalmente sacrifico un poco de rendimiento para la legibilidad del código. Su código no se verá afectado si usa algunas cuerdas aquí y allá. Y para ese bloque de código que hace cat muchas cadenas a menudo, use StringBuilder.

0

Si puede, podría pasar un buen rato y eliminar por completo el bucle for y usar el agregado?

var concatstring = mylist.Aggregate("", (acc, item) => acc + "." + item); 

¿No está seguro de la sobrecarga de esto sin embargo?

+1

Aunque es de hace 7 años ... Linq siempre es más lento que un bucle directo, porque es un bucle de adentro hacia afuera con muchas llamadas de función adicionales. Tiendo a pensar que la optimización del rendimiento siempre dará como resultado tirar a Linq en vez de incluirlo. El objetivo es la legibilidad; no rendimiento ... – FrankB

Cuestiones relacionadas