2010-07-20 7 views
7

Duplicar posible:
String concatenation vs String Builder. Performancequé operación de cadena es mejor?

Cualquier diferencia (el rendimiento y uso de memoria) entre las dos opciones siguientes?

opción

1:

StringBuilder msgEntry = new StringBuilder(); 
msgEntry.AppendLine("<" + timeTag + ">" + timeStamp + "</" + timeTag + ">"); 

opciones 2:

StringBuilder msgEntry = new StringBuilder(); 
msgEntry.Append("<"); 
msgEntry.Append(timeTag); 
msgEntry.Append(">"); 
msgEntry.Append(timeStamp); 
msgEntry.Append("</"); 
msgEntry.Append(timeTag); 
msgEntry.Append(">\n"); 
+4

A menos que ya haya detectado un problema de rendimiento, o este código se ejecuta miles de veces dentro de un bucle o algo así, la diferencia es irrelevante. Ir con la opción más legible. – JohnFx

+1

También puede valer la pena considerar el uso de algunas de las clases de XML existentes.Parece que no está familiarizado con gran parte del marco (ya que no estaba al tanto de las funciones de formato de cadena), le recomiendo que elija algo así como un libro de 21 días para leerlo perezosamente, para aprender sobre esas cosas. – overslacked

+1

Voto por volver a abrir: cuando no se utiliza en un bucle, la situación de rendimiento es diferente. En este caso específico, la concatenación de cadenas (opción 1) usaría una única llamada a String.Concat que funciona mejor que las siete llamadas a StringBuilder.Append. Estaba a punto de escribir una respuesta señalando esto ... – MartinStettner

Respuesta

27

La segunda es posiblemente ligeramente mejor en términos de uso de memoria, ya que no es necesario para calcular la cadena intermedia ... pero es menos legible, la OMI.

Personalmente me gustaría usar:

msgEntry.AppendFormat("<{0}>{1}</{0}>", timeTag, timeStamp); 

No ha mostrado lo que quiere hacer con el StringBuilder después. Si solo vas a convertirlo en una cadena, entonces utilizaría:

string text = string.Format("<{0}>{1}</{0}>", timeTag, timeStamp); 

para empezar.

¿Cómo es el rendimiento? Bueno, probablemente sea peor, después de todo, tiene que analizar la cadena de formato. Pero a menos que hayas medido esto y hayas encontrado que es el cuello de botella, ¿por qué estás preocupado?

En general:

  • Asegúrese de que su arquitectura es razonablemente eficiente - eso es difícil de cambiar más adelante.
  • Equilibre su diseño interno entre la eficiencia y la simplicidad, con énfasis en la capacidad de prueba; cambiar el diseño más tarde puede tomar un tiempo, pero por lo general debería ser posible sin problemas de compatibilidad.
  • Escriba su implementación para que sea lo más legible posible.
  • Mida el sistema para averiguar si funciona bien y dónde están los cuellos de botella. Casi nunca van a estar en un código como este. (No estamos hablando de la concatenación de cadenas en un bucle aquí, después de todo.)
  • Cuando haya encontrado un cuello de botella, probar diferentes optimizaciones y medirlos demasiado. No asuma que algo que cree que será más rápido será en realidad sea más rápido.

O la matriz para pasar a Concat ... no sabemos el tipo de timeStamp así que no podemos decir exactamente lo que está pasando allí; en la segunda forma, puede adjuntarse in situ, mientras que la primera forma puede necesitar encasillarla y luego convertirla en una cadena antes de realizar la concatenación.

La implementación exacta para la reasignación, etc. puede haber cambiado entre .NET 3.5 y .NET 4 (sé que algunos aspectos de la implementación sí lo tienen). Sin una evaluación comparativa muy cuidadosa, detestaría mucho decir qué es más rápido ... pero la legibilidad es más fácil de llamar, aunque subjetivamente.

+0

¡Jon Skeet siempre más rápido que todos los demás! Estaba escribiendo eso! –

+0

+1 Como siempre ... un paso adelante. –

+0

Es un concurso de mecanografía a veces, te digo ...;) –

3

En general, StringBuilder ... pero cuando se habla de rendimiento, la única prueba real es medición. Especialmente para MUCHOS cambios de cadena, StringBuilder es definitivamente el camino a seguir. Para un par de cuerdas ... probablemente sea más fácil agregarlas al operador +.

+0

+1 para señalar que StringBuilder siempre es mejor cuando tienes MUCHAS concatenaciones de cadenas. – Jagd

+0

¡No en este caso! Para una sola concatenación (fuera de un bucle), se haría una sola llamada a String.Concat para la primera opción. La segunda opción tomaría siete llamadas a StringBuilder.Append. – MartinStettner

+0

@Martin; "en general". Jon dijo lo mismo ... Aunque con más elocuencia que yo y con más detalles. Pero el empuje es idéntico. – Steve

2

Yo usaría .AppendFormat(); en ese caso

StringBuilder msgEntry = new StringBuilder(); 
msgEntry.AppendFormat("<{0}>{1}</{0}>", timeTag , timeStamp); 
+0

+1 Nunca me di cuenta de ese método en un generador de cuerdas antes. ¡Eso es genial! ¡no más sb.append (format (...)) para mí! – JohnFx

2

Personalmente, yo elegiría ninguno, y el uso de

msgEntry.AppendFormat("<{0}>{1}</{0}>", timeTag, timeStamp); 
0

La segunda línea es mejor que el no conseguir mucho si cualquier beneficiarían de StringBuilder en la primera. Sin embargo, para un pequeño concat de cuerdas así no me molestaría con el generador de cuerdas

1

Si eso es todo lo que estás haciendo, no uses StringBuilder. Es demasiada sobrecarga con un golpe de legibilidad.

Prueba esto:

string.Format("<{0}>{1}</{2}>", timeTag, timeStamp, timeTag); 
0

Sí.

Si va a hacer la opción 1, no tiene sentido usar StringBuilder. Todavía está haciendo la concatenación de cadenas y terminará con múltiples cadenas temporales adicionales que se crean y descartan en la memoria.

para algo como esto, que es mejor usar String.Format()

+0

Aquí solo se necesita una cadena temporal adicional; el compilador llamará a 'string.Concat (" <", timeTag,"> ", timeStamp," ")' (con conversiones cuando sea necesario). –

-1

Use siempre StringBuilder.Append() para la concatenación de cadenas. El operador de cadena + causa una nueva asignación para cada nuevo elemento.

+1

No, no es así. Llamará 'string.Concat' una vez, por lo que generará una cadena intermedia adicional. Solo debería usar 'StringBuilder.Append()' cuando realmente tenga sentido hacerlo; si está haciendo toda la concatenación en una sola expresión y quiere una cadena al final, usar + es absolutamente correcto. –

+0

Bueno, acabo de hacer una pequeña prueba. Aparentemente he estado equivocado. Gracias por la corrección. –

+0

Si tiene cadenas estáticas adyacentes separadas con el signo "+", el compilador las combinará en tiempo de compilación. Además, si concatena solo 2 o 3 cadenas, "+" supera la instancia de un objeto de generador de cadenas. – adam0101

1

He confiado en el consejo en Performance Tips and Tricks in .NET Applications de MSDN que aconseja utilizar StringBuilder para la manipulación compleja de cadenas.

Se enciende para asesorar:

soluciones de compromiso Hay algo de sobrecarga asociado con la creación de un objeto StringBuilder , tanto en el tiempo y la memoria. En una máquina con memoria rápida, un StringBuilder vale la pena si está haciendo unas cinco operaciones. Como regla general, yo diría que 10 o más operaciones de cadena es una justificación de para la sobrecarga en cualquier máquina , incluso una más lenta.

También consideraría este consejo de una optimización de código.Mostrar neto:

Es especialmente importante pre-asignar el tamaño de la cadena. Si no lo hace, StringBuilder sigue siendo más rápido, pero si puede predecir la longitud final de la cadena final, configúrelo con anticipación.

Esto se debe a que la capacidad predeterminada de un StringBuilder es 16. Cambia automáticamente de tamaño cuando se excede la capacidad, se duplica cada vez. Por lo tanto, puede tener varias modificaciones innecesarias si no establece la capacidad inicial. Puede contar el número máximo esperado de caracteres en su ejemplo e inicializar StringBuilder para que no cambie de tamaño. Eso ahorrará algo de CPU.

Y aquí es some additional advice from MSDN:

La realización de una operación de concatenación de una cadena o objeto StringBuilder depende de con qué frecuencia ocurre una asignación de memoria. Una operación de concatenación cadena siempre asigna memoria, mientras que una operación de concatenación StringBuilder solamente asigna memoria si la memoria intermedia de objetos StringBuilder es demasiado pequeña para acomodar los nuevos datos. En consecuencia, la clase String es preferible para una operación de concatenación si hay un número fijo de objetos String concatenados. En ese caso , las operaciones de concatenación individual incluso pueden combinarse en una sola operación por el compilador. Un objeto StringBuilder de es preferible para una operación de concatenación si un número arbitrario de es concatenado; por ejemplo, si un bucle concatena un número aleatorio de cadenas de entrada de usuario.

+0

Comenzaría averiguando si es o no realmente significativo antes de preocuparme por calcular el tamaño correcto para preasignar, etc. También vale la pena señalar que su primer enlace es de agosto de 2001 ... antes de que incluso apareciera .NET 1.0. Sé con certeza que la implementación de StringBuilder ha cambiado significativamente entre .NET 3.5 y .NET 4, y no me sorprendería si hubiera cambiado en otras versiones también. Todavía vale la pena evitar la concatenación en bucles, seguro ... pero las reglas generales definitivamente pueden cambiar con el tiempo. –

+0

@Jon Skeet Me doy cuenta de que el primer artículo no es reciente, pero todavía se cita con frecuencia, y si ya no fuera válido, creo que el personal de Microsoft lo eliminaría o actualizaría. Y en el tercer artículo, que se aplica a .Net 4, mencionan el cambio de tamaño en "Consideraciones de rendimiento". Y dado que a veces es muy fácil calcular la capacidad máxima necesaria para un StringBuilder, como lo sería en este caso, definitivamente lo haría si las concatenaciones de cadenas son frecuentes en la aplicación. Es un esfuerzo tan pequeño. – DOK

+0

¿Cuán frecuente es frecuente? No lo haría a menos que tengas una buena razón para hacerlo. ¿Cuánto esfuerzo dirías que es en este caso? ¿Qué pasa cuando estás leyendo el código? ¿Cómo vas a calcular la longitud de 'timeStamp'? –

0

El primer ejemplo me parece incorrecto. ¿De qué sirve crear un objeto StringBuider cuando está concatenando cadenas antes de pasarlas a StringBuilder?

También tenga en cuenta que:

  • Anexar vuelve instancia de StringBuilder, por lo que llama a añadir y AppendLine se pueden encadenar juntos
  • Al final del segundo ejemplo, puede usar AppendLine (">") en lugar de append ("> \ n")
 StringBuilder msgEntry = new StringBuilder(); 
    msgEntry.Append("<") 
     .Append(timeTag) 
     .Append(">") 
     .Append(timeStamp) 
     .Append("</") 
     .Append(timeTag) 
     .AppendLine(">"); 

Personalmente me gustaría hacer

 string.Format("<{0}>{1}</{0}>", timeTag, timeStamp);

a menos que necesite el StringBuilder para otra cosa.

Cuestiones relacionadas