Me preguntaba acerca de StringBuilder y tengo una pregunta que tenía la esperanza de que la comunidad sería capaz de explicar.

Vamos a olvidar acerca de la legibilidad del código, el cual de estos es más rápido y por qué?

StringBuilder.Append:

StringBuilder sb = new StringBuilder();
sb.Append(string1);
sb.Append("----");
sb.Append(string2);

StringBuilder.AppendFormat:

StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}----{1}",string1,string2);
  • Todos los que comentarios con una respuesta absoluta debe obtener -1, ya que no están teniendo en cuenta las longitudes de cadena1 y cadena2. Se podrían crear diferentes pruebas con diferentes valores para cadena1 y cadena2 que girará la respuesta de cualquier manera.
  • Append = Cadena.Formato De + Append. Por lo tanto .Append() es más rápido y más eficiente que .AppendFormat(). Este punto de referencia la prueba. Echa un vistazo a mi respuesta con la prueba de los resultados.
  • Una gran cantidad de personas para quienes el inglés es un segundo idioma parecen pensar que la «duda» == «pregunta» pero eso no es realmente el caso. No tiene sentido para nadie, pero el escéptico explicar por qué se duda. Sin duda podemos responder a una pregunta para usted, aunque!
InformationsquelleAutor Sergio | 2009-04-02

9 Comentarios

  1. 41

    Es imposible decir, no sabiendo el tamaño de string1 y string2.

    Con la llamada a AppendFormat, va a asignar previamente el búfer sólo una vez dada la longitud de la cadena de formato y las cadenas que se inserta y, a continuación, concatenar todo y la inserta en el búfer. Por muy grandes cadenas, esto será una ventaja sobre independiente llamadas a Añadir cual podría causar que el búfer para ampliar varias veces.

    Sin embargo, las tres llamadas a Append podría o no activar el crecimiento del búfer y los que se realiza la comprobación de cada llamada. Si las cadenas son lo suficientemente pequeños y no búfer de expansión se activa, entonces será más rápido que la llamada a AppendFormat, ya que no se tiene que analizar la cadena de formato para averiguar dónde hacer los reemplazos.

    Se necesita más información para una respuesta definitiva

    Cabe señalar que existe poca discusión sobre el uso de la estática Concat método String clase (Jon respuesta utilizando AppendWithCapacity me recordó a este). Sus resultados muestran que para ser el mejor de los casos (suponiendo que usted no tiene que tomar ventaja de determinados especificador de formato). String.Concat hace la misma cosa en que van a condicionar la longitud de las cadenas para concatenar y asignar previamente el buffer (con un poco más de la sobrecarga debido a las construcciones de bucle a través de los parámetros). Es el rendimiento va a ser comparable a la de Jon AppendWithCapacity método.

    O, simplemente, la llanura operador de suma, ya que se compila en una llamada a String.Concat de todos modos, con la advertencia de que todas las adiciones se encuentran en la misma expresión:

    //One call to String.Concat.
    string result = a + b + c;

    NO

    //Two calls to String.Concat.
    string result = a + b;
    result = result + c;

    Para todos aquellos que poner el código de la prueba

    Usted necesita para ejecutar los casos de prueba en separado se ejecuta (o, al menos, realizar un GC entre la medición de ejecuciones de prueba independiente). La razón de esto es que si usted diga, 1.000.000 de carreras, la creación de un nuevo StringBuilder en cada iteración del bucle para una prueba y, a continuación, ejecutar la siguiente prueba que se repite el mismo número de veces, la creación de un adicionales 1.000.000 de StringBuilder de los casos, la GC más que probable que paso durante la segunda prueba y dificultan su tiempo.

    • +1 Buen punto acerca de la necesidad de más datos. Creo que la mayoría de nosotros nos dio una respuesta definitiva, sin tener en cuenta el hecho de que las diferentes entradas serían significativos.
    • +1 punto. Si los ejemplos fueron cambiados para asignar previamente espacio para las cadenas a través de la Capacidad de la propiedad, entonces la diferencia sería sólo el formato de la cadena.
    • Usted puede llamar a la GC.Collect() entre pistas de curso. No será muy de la misma, pero muy cerca.
    • Skeet: respuesta Actualizada en consecuencia.
    • Ahora que he añadido el «AppendWithCapacity» la prueba en mi respuesta, tengo la sospecha de que iba a ser duro para construir ejemplos en los que eso no iba a ser el más rápido, excepto para las cadenas vacías.
    • Skeet: No hay necesidad de hacer eso, de Cadena.Concat hace exactamente la misma cosa.
    • Skeet: Actualizado para reflejar Cadena.Concat.
    • No, De Cadena.Concat no hacer lo mismo exacto cosa – usted termina con una cadena, no un StringBuilder. Creo que es muy probable que en el código real es probable que usted quiere hacer más anexa antes o después. (cont)
    • La diferencia entre «el resultado es una cadena» y «resultado es un StringBuilder» es potencialmente muy importante. Estoy de acuerdo en que si lo que desea es una cadena que sólo debe utilizar un + «—-» + b, aunque.
    • Skeet: Si tener un StringBuilder para hacer más con él es el resultado deseado (porque se pasa todo), estoy de acuerdo; pero para un conjunto fijo de conocidos entradas (que es un caso muy común) en la Cadena.Concat es la mejor opción.

  2. 22

    casperOne es correcta. Una vez que alcanzan un cierto umbral, la Append() método es más lento que AppendFormat(). Aquí están las diferentes longitudes y transcurrido garrapatas de 100.000 iteraciones de cada método:

    Longitud: 1

    Append()       - 50900
    AppendFormat() - 126826

    Longitud: 1000

    Append()       - 1241938
    AppendFormat() - 1337396

    Longitud: 10,000

    Append()       - 12482051
    AppendFormat() - 12740862

    Longitud: 20,000

    Append()       - 61029875
    AppendFormat() - 60483914

    Cuando las cadenas de caracteres con una longitud de cerca de 20.000 son introducidas, el AppendFormat() función ligeramente superar Append().

    ¿Por qué sucede esto? Ver casperOne la respuesta.

    Edición:

    Volví a ejecutar cada prueba de forma individual bajo la configuración de Lanzamiento y actualizado de los resultados.

    • Podría publicar el código? Me gustaría probar con un preset de la capacidad, pero no quiere reinvwent su rueda.
    • pastebin.com/m1d0c1b47
    • ¿Qué hace exactamente la longitud consulte aquí? La longitud actual de la StringBuilder, o la longitud de la cadena(s) que se anexa?
  3. 12

    casperOne es totalmente preciso que depende de los datos. Sin embargo, supongamos que usted está escribiendo esto como una biblioteca de clases para el 3 de partes para consumir, que tendría que utilizar?

    Una opción sería la de obtener lo mejor de ambos mundos de trabajo fuera de la cantidad de datos que vamos a tener que agregar y, a continuación, utilizar StringBuilder.EnsureCapacity para asegurarse de que sólo tiene un único búfer de tamaño.

    Si yo no fuera demasiado molestado a pesar de que, yo uso la Append x3 – parece «más probable» para ser más rápido, como el análisis de la cadena de tokens de formato en cada llamada es claramente hacer el trabajo.

    Nota que le he pedido al equipo de BCL para una especie de «caché formateador» que se pueden crear utilizando una cadena de formato y, a continuación, volver a utilizar varias veces. Es una locura que el marco para analizar la cadena de formato cada vez que se usa.

    EDIT: Bueno, he editado Juan del código un poco de flexibilidad y añadido un «AppendWithCapacity», que funciona de la capacidad necesaria en primer lugar. Aquí están los resultados para las diferentes longitudes de longitud 1 he utilizado 1.000.000 de iteraciones; para todas las demás longitudes he utilizado 100,000. (Esto fue sólo para obtener sensible de tiempos de ejecución.) Todas las horas están en millis.

    Lamentablemente tablas no funcionan ASÍ. Las longitudes de 1, 1000, 10000, 20000

    Veces:

    • Anexar: 162, 475, 7997, 17970
    • AppendFormat: 392, 499, 8541, 18993
    • AppendWithCapacity: 139, 189, 1558, 3085

    Así como sucedió, nunca vi AppendFormat vencer a Añadir – pero yo hizo ver AppendWithCapacity ganar por un margen sustancial.

    Aquí el código completo:

    using System;
    using System.Diagnostics;
    using System.Text;
    public class StringBuilderTest
    {            
    static void Append(string string1, string string2)
    {
    StringBuilder sb = new StringBuilder();
    sb.Append(string1);
    sb.Append("----");
    sb.Append(string2);
    }
    static void AppendWithCapacity(string string1, string string2)
    {
    int capacity = string1.Length + string2.Length + 4;
    StringBuilder sb = new StringBuilder(capacity);
    sb.Append(string1);
    sb.Append("----");
    sb.Append(string2);
    }
    static void AppendFormat(string string1, string string2)
    {
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}----{1}", string1, string2);
    }
    static void Main(string[] args)
    {
    int size = int.Parse(args[0]);
    int iterations = int.Parse(args[1]);
    string method = args[2];
    Action<string,string> action;
    switch (method)
    {
    case "Append": action = Append; break;
    case "AppendWithCapacity": action = AppendWithCapacity; break;
    case "AppendFormat": action = AppendFormat; break;
    default: throw new ArgumentException();
    }
    string string1 = new string('x', size);
    string string2 = new string('y', size);
    //Make sure it's JITted
    action(string1, string2);
    GC.Collect();
    Stopwatch sw = Stopwatch.StartNew();
    for (int i=0; i < iterations; i++)
    {
    action(string1, string2);
    }
    sw.Stop();
    Console.WriteLine("Time: {0}ms", (int) sw.ElapsedMilliseconds);
    }
    }
    • Skeet: no he mirado, pero podría ser un compilado de Regex ser una solución a la caché del formateador de idea? Tengo la esperanza es lo suficientemente inteligente como para pre-asignar la salida, y evitaría que el análisis de la cadena de formato cada vez.
    • El regex sólo de análisis, el formato no tan lejos como puedo ver. Por cierto, en el anterior al considerar EnsureCapacity me había ignorado el hecho de que el código crea el StringBuilder sí mismo. Acaba de pasar con la capacidad necesaria en el constructor.
    • Skeet: no le va a hacer el análisis, pero eso es la mitad del problema ¿no? Si usted está haciendo recta de reemplazo, no es mucho de un problema. Sin embargo, usted no consigue el efecto de ser capaz de almacenar las cadenas de formato cuando se utiliza la Expresión regular (especialmente si desea dar formato a los argumentos).
    • aquí el código: pastebin.com/m1d0c1b47
    • Todavía no veo cómo te gustaría hacer el reemplazo. Pero sin la capacidad de hacer cadenas de formato, realmente no es equivalente. Un StringFormatter tipo definitivamente sería útil.
    • Recuerdo que usted ha mencionado su ‘caché formato de la idea de un tiempo, y he estado pensando acerca de la implementación de la mía propia. Por supuesto, para ser realmente útil sería necesario exactamente coincide con la normal de la Cadena.Format() de análisis, y no puedo usar el reflector en el trabajo 🙁
    • Sí, esa es la parte difícil – llegar exactamente a la derecha. Es sin duda algo que el equipo de BCL debería estar trabajando. Afortunadamente, uno de los del equipo de BCL leer la entrada en el blog y le gustó la idea, así que tal vez un día…
    • Skeet: Su «AppendWithCapacity» es en realidad «de la Cadena.Concat», así que no hay necesidad para que supletoria el código desordenado.
    • Yo estaba asumiendo que el punto al final con un StringBuilder aunque, por lo que podríamos agregar más a él. Sospecho que en la vida real, la StringBuilder se pasa con algunos datos ya – en cuyo caso EnsureCapacity() es el equivalente de respuesta, básicamente. De la cadena.Concat no ayuda, a continuación,

  4. 6

    Añadir será más rápido en la mayoría de los casos, porque hay muchas sobrecargas a que el método que permiten al compilador para llamar al método correcto. Puesto que usted está utilizando Strings la StringBuilder puede utilizar el String sobrecarga para Append.

    AppendFormat toma un String y, a continuación, un Object[] lo que significa que el formato deberá ser analizado y cada Object en la matriz tendrá que ser ToString'd antes de que pueda ser añadido a la StringBuilder's matriz interna.

    Nota: A casperOne punto – es difícil dar una respuesta exacta, sin más datos.

  5. 2

    StringBuilder también ha cascada anexa: Append() devuelve el StringBuilder sí mismo, así que usted puede escribir su código como este:

    StringBuilder sb = new StringBuilder();
    sb.Append(string1)
    .Append("----")
    .Append(string2);

    Limpio, y genera menos IL-código (a pesar de que en realidad es una micro-optimización).

  6. 1

    De perfil del curso para saber con certeza en cada caso.

    Que dijo, creo que en general va a ser la primera porque usted no está en repetidas ocasiones el análisis de la cadena de formato.

    Sin embargo, la diferencia sería muy pequeña. Hasta el punto de que usted realmente debería considerar el uso de AppendFormat en la mayoría de los casos, de todos modos.

  7. 0

    Yo supongo que fue el llamado que hizo la menor cantidad de trabajo. Anexar sólo concatena cadenas, donde AppendFormat está haciendo sustituciones de cadena. Por supuesto, en estos días, usted nunca puede decir…

    • -1, Anexar no concatenar cadenas de caracteres. Se añade a su interno matriz de caracteres.
    • Lo siento, concatena los personajes …
  8. 0

    1 debe ser más rápido porque es simplemente añadiendo las cuerdas mientras que el 2 tiene que crear una cadena basada en un formato y, a continuación, añadir la cadena. Así que hay un paso adicional en la haya.

  9. 0

    Más rápido es de 1 en su caso, sin embargo no es una comparación justa. Usted debe preguntar a StringBuilder.AppendFormat() vs StringBuilder.Append(string.Format()) – donde el primero es más rápido debido a la interna de trabajo con la matriz de char.

    Su segunda opción es más legible, aunque.

    • de la cadena.Format() crea un objeto StringBuilder internamente, por lo que StringBuilder.AppendFormat() es básicamente la misma cadena.(Formato)
    • Si bien esto es probablemente cierto, hay dos pasos a seguir cuando se hace Append(string.Format()) – en primer lugar, el Formato y, a continuación, su contenido tiene que ser copiado a StringBuilder del contenido. Al hacer AppendFormat sólo hay un paso.
    • Y es por eso que nunca he considerado el «StringBuilder.Append(string.Format())» opción en el primer lugar 😉

Dejar respuesta

Please enter your comment!
Please enter your name here