viernes, 3 de julio de 2009

Concatenación de Strings (Ineficiencia demostrada)

Recientemente tuve que analizar el código de una página Web que presentaba un comportamiento bastante ineficiente.

Para focalizar el problema utilicé una excelente herramienta () que no viene al caso ahora. En fin que después de detectado y analizado el método donde se producía el cuello de botella, descubrimos que la ineficiencia se debía a una actualización de una variable de tipo string dentro de un ciclo medianamente grande, para que me entendáis, el código despejándolo un poco era algo así:

////Ejemplo de código ineficiente

string sNewBuffer = string.Empty;

for (int i = 0; i < 50000; i++)

{

sNewBuffer += i.ToString();

}

return sNewBuffer;

Al detectar semejante mala práctica, modificamos el código dejándolo de la siguiente manera:

////Ejemplo de código eficiente

StringBuilder sbNewBuffer = new StringBuilder();

for (int i = 0; i < 50000; i++)

{

sbNewBuffer.Append(i.ToString());

}

return sbNewBuffer.ToString();

Como veréis la diferencia entre un código y el otro es que remplazamos el uso de una variable string por otra de tipo StringBuilder. Y el resultado es el mismo pero con una notable mejora de eficiencia.

Explicación: Las cadenas de .Net Framework con invariables (o sea, el texto al que se hace referencia es de sólo lectura después de la asignación inicial). Esto provoca que internamente, para concatenar un string, lo que se hace es crear una nueva instancia de string, copiar el string actual en esa nueva instancia y borrar la instancia original.

Conclusión: La concatenación de strings es extremadamente ineficiente.

Siempre que podáis, aunque sea para las operaciones más simples, utilizad el StringBuilder frente a la concatenación de strings... y si es para operaciones más costosas ni os lo penséis!!!!

6 comentarios:

  1. Esto es algo que microsoft ya viene arrastrando desde sus versiones anteriores, cuando acabará el gigante de la industria solucionarlo de una puta vez...

    ResponderEliminar
  2. Mi consejo es que uses StringBuilder, aun en las operaciones más simples.

    Salu2,
    Derbis

    ResponderEliminar
  3. Derbis alcarando un poco tu explicación. El string se borra cuando lo libera el recolector por lo tanto puede permanecer un x tiempo en memoria sin borrarse y eso es lo que provoca el cuello de botella. No inmediatamente como puedo entender de tu explicación. Saludos

    ResponderEliminar
  4. Efectivamente MelDJ,

    El espacio de memoria reservado para la cadena original, solo se libera para la recolección de elementos no utilizados, ya que ninguna otra variable contiene una referencia a él, y no estará disponible dicho espacio de memoria, hasta que el recolector de basura haga su trabajo.

    salu2,
    Derbis

    ResponderEliminar
  5. No necesitas, en tu ejemplo, hacer un ToString() a la variable del bucle ya que el metodo Append del StringBuilder convierte lo hace automáticamente

    ResponderEliminar
  6. Llevas razón en lo que dices Anónimo, pero de todas formas, creo q es más esclarezedor el ponerlo. De todas fromas, es valida tu aclaración.

    Salu2,
    Derbis

    ResponderEliminar