Entiendo los beneficios de StringBuilder.
Pero si quiero concatenar 2 cadenas, supongo que es mejor (más rápido) hacerlo sin StringBuilder. ¿Es esto correcto?
¿En qué punto (número de cadenas) es mejor utilizar StringBuilder?
c#
stringbuilder
Shiraz Bhaiji
fuente
fuente
Respuestas:
Le sugiero encarecidamente que lea La triste tragedia del teatro de microoptimización , de Jeff Atwood.
Trata la concatenación simple frente a StringBuilder frente a otros métodos.
Ahora, si quieres ver algunos números y gráficos, sigue el enlace;)
fuente
Eso es correcto, puede encontrar el por qué exactamente explicado muy bien en:
http://www.yoda.arachsys.com/csharp/stringbuilder.html
En resumen: si puedes concatinar cadenas de una sola vez, como
var result = a + " " + b + " " + c + ..
está mejor sin StringBuilder porque solo se realiza una copia (la longitud de la cadena resultante se calcula de antemano);
Para estructuras como
var result = a; result += " "; result += b; result += " "; result += c; ..
se crean nuevos objetos cada vez, por lo que debería considerar StringBuilder.
Al final, el artículo resume estas reglas generales:
fuente
System.String es un objeto inmutable; significa que cada vez que modifiques su contenido, asignará una nueva cadena y esto lleva tiempo (¿y memoria?). Con StringBuilder, modifica el contenido real del objeto sin asignar uno nuevo.
Por lo tanto, use StringBuilder cuando necesite hacer muchas modificaciones en la cadena.
fuente
Realmente no ... deberías usar StringBuilder si concatenas cadenas grandes o tienes muchas concatenaciones, como en un bucle.
fuente
StringBuilder
solo si el bucle o la concatenación es un problema de rendimiento para las especificaciones.string s = "abcd"
, al menos eso es lo último Escuché ... aunque, con variables sería, muy probablemente, Concat.a + "hello" + "somethingelse"
y nunca tuve que preocuparme por eso. Si se convierte en un problema, usaré StringBuilder. Pero no me preocupé por ello en primer lugar y pasé menos tiempo escribiéndolo.Aquí hay una aplicación de prueba simple para demostrar el punto:
class Program { static void Main(string[] args) { const int testLength = 30000; var StartTime = DateTime.Now; //TEST 1 - String StartTime = DateTime.Now; String tString = "test string"; for (int i = 0; i < testLength; i++) { tString += i.ToString(); } Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString()); //result: 2000 ms //TEST 2 - StringBuilder StartTime = DateTime.Now; StringBuilder tSB = new StringBuilder("test string"); for (int i = 0; i < testLength; i++) { tSB.Append(i.ToString()); } Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString()); //result: 4 ms Console.ReadLine(); } }
Resultados:
30.000 iteraciones
1000 iteraciones
500 iteraciones
fuente
Parafrasear
Generalmente uso el generador de cadenas para cualquier bloque de código que resulte en la concatenación de tres o más cadenas.
fuente
No hay una respuesta definitiva, solo reglas generales. Mis propias reglas personales son algo como esto:
StringBuilder
.StringBuilder
.Si no es así, use un
StringBuilder
.fuente
Si. Pero lo que es más importante, es mucho más legible usar una vainilla
String
en tales situaciones. Usarlo en un bucle, por otro lado, tiene sentido y también puede ser tan legible como la concatenación.Sería cauteloso con las reglas generales que citan números específicos de concatenación como umbral. Usarlo en bucles (y solo en bucles) es probablemente igual de útil, más fácil de recordar y tiene más sentido.
fuente
Siempre que pueda escribir físicamente el número de concatenaciones (a + b + c ...) no debería haber una gran diferencia. N al cuadrado (en N = 10) es una desaceleración de 100 veces, lo que no debería ser tan malo.
El gran problema es cuando está concatenando cientos de cadenas. A N = 100, obtienes una ralentización de 10000 veces. Lo cual es bastante malo.
fuente
Dado que es difícil encontrar una explicación para esto que no esté influenciado por opiniones o seguido por una batalla de orgullo, pensé en escribir un poco de código en LINQpad para probarlo yo mismo.
Descubrí que usar cadenas de tamaño pequeño en lugar de usar i.ToString () cambia los tiempos de respuesta (visibles en pequeños bucles).
La prueba utiliza diferentes secuencias de iteraciones para mantener las mediciones de tiempo en rangos sensiblemente comparables.
Copiaré el código al final para que pueda probarlo usted mismo (results.Charts ... Dump () no funcionará fuera de LINQPad).
Salida (eje X: número de iteraciones probadas, eje Y: tiempo empleado en tics):
Secuencia de iteraciones: 2, 3, 4, 5, 6, 7, 8, 9, 10
Secuencia de iteraciones: 10, 20, 30, 40, 50, 60, 70, 80
Secuencia de iteraciones: 100, 200, 300, 400, 500
Código (escrito con LINQPad 5):
void Main() { Test(2, 3, 4, 5, 6, 7, 8, 9, 10); Test(10, 20, 30, 40, 50, 60, 70, 80); Test(100, 200, 300, 400, 500); } void Test(params int[] iterationsCounts) { $"Iterations sequence: {string.Join(", ", iterationsCounts)}".Dump(); int testStringLength = 10; RandomStringGenerator.Setup(testStringLength); var sw = new System.Diagnostics.Stopwatch(); var results = new Dictionary<int, TimeSpan[]>(); // This call before starting to measure time removes initial overhead from first measurement RandomStringGenerator.GetRandomString(); foreach (var iterationsCount in iterationsCounts) { TimeSpan elapsedForString, elapsedForSb; // string sw.Restart(); var str = string.Empty; for (int i = 0; i < iterationsCount; i++) { str += RandomStringGenerator.GetRandomString(); } sw.Stop(); elapsedForString = sw.Elapsed; // string builder sw.Restart(); var sb = new StringBuilder(string.Empty); for (int i = 0; i < iterationsCount; i++) { sb.Append(RandomStringGenerator.GetRandomString()); } sw.Stop(); elapsedForSb = sw.Elapsed; results.Add(iterationsCount, new TimeSpan[] { elapsedForString, elapsedForSb }); } // Results results.Chart(r => r.Key) .AddYSeries(r => r.Value[0].Ticks, LINQPad.Util.SeriesType.Line, "String") .AddYSeries(r => r.Value[1].Ticks, LINQPad.Util.SeriesType.Line, "String Builder") .DumpInline(); } static class RandomStringGenerator { static Random r; static string[] strings; public static void Setup(int testStringLength) { r = new Random(DateTime.Now.Millisecond); strings = new string[10]; for (int i = 0; i < strings.Length; i++) { strings[i] = Guid.NewGuid().ToString().Substring(0, testStringLength); } } public static string GetRandomString() { var indx = r.Next(0, strings.Length); return strings[indx]; } }
fuente
No creo que haya una línea muy fina entre cuándo usar y cuándo no. A menos que, por supuesto, alguien haya realizado pruebas exhaustivas para obtener las condiciones de oro.
Para mí, no usaré StringBuilder si solo concateno 2 cadenas enormes. Si hay un bucle con un recuento indeterminista, es probable que lo haga, incluso si el bucle puede ser un recuento pequeño.
fuente
Una sola concatenación no vale la pena usar StringBuilder. Por lo general, he usado 5 concatenaciones como regla general.
fuente