practices example best appendformat c# vb.net performance stringbuilder string.format

c# - example - Es String.Format tan eficiente como StringBuilder



stringbuilder list c# (12)

En ambos casos anteriores quiero inyectar una o más cadenas en el medio de una cadena de plantilla predefinida.

En ese caso, sugeriría que String.Format sea el más rápido porque está diseñado para ese propósito exacto.

Supongamos que tengo un generador de cuerdas en C # que hace esto:

StringBuilder sb = new StringBuilder(); string cat = "cat"; sb.Append("the ").Append(cat).(" in the hat"); string s = sb.ToString();

sería tan eficiente o más eficiente como tener:

string cat = "cat"; string s = String.Format("The {0} in the hat", cat);

Si es así, ¿por qué?

EDITAR

Después de algunas respuestas interesantes, me di cuenta de que probablemente debería haber sido un poco más claro en lo que estaba preguntando. No estaba tanto preguntando por cuál era más rápido para concatenar una cuerda, sino que es más rápido para inyectar una cuerda en otra.

En ambos casos anteriores quiero inyectar una o más cadenas en el medio de una cadena de plantilla predefinida.

Perdón por la confusion


Creo que en la mayoría de los casos, como esta claridad, y no la eficiencia, debería ser tu mayor preocupación. A menos que esté aplastando toneladas de cuerdas, o construyendo algo para un dispositivo móvil de menor potencia, esto probablemente no afectará mucho su velocidad de carrera.

He descubierto que, en los casos en que estoy creando cadenas de una manera bastante lineal, hacer concatenaciones rectas o utilizar StringBuilder es tu mejor opción. Sugiero esto en los casos en que la mayoría de la cadena que estás creando es dinámica. Como muy poco del texto es estático, lo más importante es que está claro dónde se coloca cada fragmento de texto dinámico en caso de que sea necesario actualizarlo en el futuro.

Por otro lado, si estás hablando de una gran cantidad de texto estático con dos o tres variables, incluso si es un poco menos eficiente, creo que la claridad que obtienes de la cadena. El formato hace que valga la pena. Lo usé a principios de esta semana cuando tuve que colocar un pedacito de texto dinámico en el centro de un documento de 4 páginas. Será más fácil actualizar ese gran trozo de texto si está en una sola pieza que tener que actualizar tres piezas que concatenas juntas.


De la documentación de MSDN :

La ejecución 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 StringBuilder solo asigna memoria si el búfer de objetos StringBuilder es demasiado pequeño para acomodar los datos nuevos. En consecuencia, la clase String es preferible para una operación de concatenación si se concatena un número fijo de objetos String. En ese caso, las operaciones de concatenación individuales incluso podrían combinarse en una única 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.


Ejecuté algunos puntos de referencia de rendimiento rápido, y para 100.000 operaciones promedió más de 10 ejecuciones, el primer método (generador de cadenas) toma casi la mitad del tiempo del segundo (formato de cadena).

Entonces, si esto no es frecuente, no importa. Pero si se trata de una operación común, entonces es posible que desee utilizar el primer método.


Esperaría que String.Format fuera más lento: tiene que analizar la cadena y luego concatenarla.

Par de notas:

  • El formato es el camino a seguir para las cadenas visibles para el usuario en aplicaciones profesionales; esto evita los errores de localización
  • Si conoce la longitud de la cadena resultante de antemano, use el constructor StringBuilder (Int32) para predefinir la capacidad

Oh, también, el más rápido sería:

string cat = "cat"; string s = "The " + cat + " in the hat";



Realmente depende. Para cadenas pequeñas con pocas concatenaciones, en realidad es más rápido solo agregar las cadenas.

String s = "String A" + "String B";

Pero para cadenas más grandes (cadenas muy grandes), es más eficiente usar StringBuilder.


Si solo porque string.Format no hace exactamente lo que usted podría pensar, aquí hay una repetición de las pruebas 6 años después en Net45.

Concat sigue siendo el más rápido, pero en realidad es menos del 30% de diferencia. StringBuilder y el formato difieren en apenas un 5-10%. Obtuve variaciones del 20% ejecutando las pruebas algunas veces.

Milisegundos, un millón de iteraciones:

  • Concatenación: 367
  • Nuevo stringBuilder para cada clave: 452
  • Cache StringBuilder: 419
  • string.Format: 475

La lección que tomo es que la diferencia en el rendimiento es trivial y por lo tanto no debería evitar que escriba el código legible más simple que pueda. Lo cual para mi dinero es a menudo pero no siempre a + b + c .

const int iterations=1000000; var keyprefix= this.GetType().FullName; var maxkeylength=keyprefix + 1 + 1+ Math.Log10(iterations); Console.WriteLine("KeyPrefix /"{0}/", Max Key Length {1}",keyprefix, maxkeylength); var concatkeys= new string[iterations]; var stringbuilderkeys= new string[iterations]; var cachedsbkeys= new string[iterations]; var formatkeys= new string[iterations]; var stopwatch= new System.Diagnostics.Stopwatch(); Console.WriteLine("Concatenation:"); stopwatch.Start(); for(int i=0; i<iterations; i++){ var key1= keyprefix+":" + i.ToString(); concatkeys[i]=key1; } Console.WriteLine(stopwatch.ElapsedMilliseconds); Console.WriteLine("New stringBuilder for each key:"); stopwatch.Restart(); for(int i=0; i<iterations; i++){ var key2= new StringBuilder(keyprefix).Append(":").Append(i.ToString()).ToString(); stringbuilderkeys[i]= key2; } Console.WriteLine(stopwatch.ElapsedMilliseconds); Console.WriteLine("Cached StringBuilder:"); var cachedSB= new StringBuilder(maxkeylength); stopwatch.Restart(); for(int i=0; i<iterations; i++){ var key2b= cachedSB.Clear().Append(keyprefix).Append(":").Append(i.ToString()).ToString(); cachedsbkeys[i]= key2b; } Console.WriteLine(stopwatch.ElapsedMilliseconds); Console.WriteLine("string.Format"); stopwatch.Restart(); for(int i=0; i<iterations; i++){ var key3= string.Format("{0}:{1}", keyprefix,i.ToString()); formatkeys[i]= key3; } Console.WriteLine(stopwatch.ElapsedMilliseconds); var referToTheComputedValuesSoCompilerCantOptimiseTheLoopsAway= concatkeys.Union(stringbuilderkeys).Union(cachedsbkeys).Union(formatkeys).LastOrDefault(x=>x[1]==''-''); Console.WriteLine(referToTheComputedValuesSoCompilerCantOptimiseTheLoopsAway);


String.Format utiliza StringBuilder internamente ... así que lógicamente eso lleva a la idea de que sería un poco menos eficiente debido a más sobrecarga. Sin embargo, una simple concatenación de cadenas es el método más rápido de inyectar una cadena entre otras dos ... en un grado significativo. Esta evidencia fue demostrada por Rico Mariani en su primera prueba de rendimiento, hace años. El hecho simple es que concatenaciones ... cuando se conoce el número de partes de la secuencia (sin limitación ... podrías concatenar mil partes ... siempre que sepas que siempre son 1000 partes) ... siempre son más rápidas que StringBuilder o String .Formato. Se pueden realizar con una única asignación de memoria y una serie de copias de memoria. Here está la prueba

Y aquí está el código real para algunos métodos String.Concat, que finalmente llaman FillStringChecked que usa punteros para copiar memoria (extraídos a través de Reflector):

public static string Concat(params string[] values) { int totalLength = 0; if (values == null) { throw new ArgumentNullException("values"); } string[] strArray = new string[values.Length]; for (int i = 0; i < values.Length; i++) { string str = values[i]; strArray[i] = (str == null) ? Empty : str; totalLength += strArray[i].Length; if (totalLength < 0) { throw new OutOfMemoryException(); } } return ConcatArray(strArray, totalLength); } public static string Concat(string str0, string str1, string str2, string str3) { if (((str0 == null) && (str1 == null)) && ((str2 == null) && (str3 == null))) { return Empty; } if (str0 == null) { str0 = Empty; } if (str1 == null) { str1 = Empty; } if (str2 == null) { str2 = Empty; } if (str3 == null) { str3 = Empty; } int length = ((str0.Length + str1.Length) + str2.Length) + str3.Length; string dest = FastAllocateString(length); FillStringChecked(dest, 0, str0); FillStringChecked(dest, str0.Length, str1); FillStringChecked(dest, str0.Length + str1.Length, str2); FillStringChecked(dest, (str0.Length + str1.Length) + str2.Length, str3); return dest; } private static string ConcatArray(string[] values, int totalLength) { string dest = FastAllocateString(totalLength); int destPos = 0; for (int i = 0; i < values.Length; i++) { FillStringChecked(dest, destPos, values[i]); destPos += values[i].Length; } return dest; } private static unsafe void FillStringChecked(string dest, int destPos, string src) { int length = src.Length; if (length > (dest.Length - destPos)) { throw new IndexOutOfRangeException(); } fixed (char* chRef = &dest.m_firstChar) { fixed (char* chRef2 = &src.m_firstChar) { wstrcpy(chRef + destPos, chRef2, length); } } }

Por lo que entonces:

string what = "cat"; string inthehat = "The " + what + " in the hat!";

¡Disfrutar!


Yo sugeriría que no, ya que String.Format no fue diseñado para la concatenación, fue diseñado para formatear el resultado de varias entradas, como una fecha.

String s = String.Format("Today is {0:dd-MMM-yyyy}.", DateTime.Today);


String.Format utiliza un StringBuilder internamente:

public static string Format(IFormatProvider provider, string format, params object[] args) { if ((format == null) || (args == null)) { throw new ArgumentNullException((format == null) ? "format" : "args"); } StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8)); builder.AppendFormat(provider, format, args); return builder.ToString(); }

El código anterior es un fragmento de mscorlib, por lo que la pregunta es "¿Es StringBuilder.Append() más rápido que StringBuilder.AppendFormat() "?

Sin una evaluación comparativa, probablemente diría que el ejemplo de código anterior se ejecutará más rápidamente con .Append() . Pero es una suposición, intente comparar y / o perfilar los dos para obtener una comparación adecuada.

Este tipo, Jerry Dixon, hizo una evaluación comparativa:

http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

Actualizado:

Lamentablemente, el enlace de arriba ha muerto desde entonces. Sin embargo, todavía hay una copia en Way Back Machine:

http://web.archive.org/web/20090417100252/http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

Al final del día, depende de si el formato de cadena se va a llamar repetitivamente, es decir, está procesando texto de manera seria en más de 100 megabytes de texto, o si se llama cuando un usuario hace clic en un botón de vez en cuando. A menos que esté haciendo un gran trabajo de procesamiento por lotes, me quedaría con String.Format, ayuda a leer el código. Si sospecha que hay un cuello de botella perf entonces pegue un perfilador en su código y vea dónde está realmente.