.NET :: Rendimiento iterando cadenas
Artículo :: Programación :: .NET
Rendimiento iterando cadenas
Introducción
¿Que es más rápido y más productivo cuando escribimos código?, ¿escribir menos líneas de código o escribir más líneas de código?. Lo cierto es que no siempre es más óptimo escribir menos líneas de código, y todo en la informática, tiene relación con la palabra «depende«, algo que a algunos les saca de sus casillas, pero es que es así, como la vida misma.
El quiz de saber que hacer cuando escribimos código, está en saber que líneas o instrucciones de código son más óptimas o cuales son menos óptimas que otras en un determinado momento.
A veces el escribir menos código no aumenta el rendimiento de las aplicaciones. Todo depende de lo que haya por debajo, y como programadores, nuestra obligación es conocer también algunos aspectos generales de uso común que muchas veces, por las prisas, pasan desapercibidos.
Una de esas tareas que pasa desapercibida por el programador, es la que tiene que ver con el trabajo con cadenas de texto. Este artículo, trata precisamente de esto, de cómo usar de forma óptima cadenas de texto a la hora de iterarlas, para lo cuál estudiaremos tres comportamientos diferentes con tres resultados sorprendentes.
Analizando los supuestos
Partamos entonces de un objetivo general. Supongamos que queremos iterar cadenas de texto para volcarlas en un control TextBox. Imaginemos entonces, las tres siguientes posibilidades:
1) Iteramos una cadena de texto e insertamos el valor de esta cadena de texto en el control TextBox. Esta forma de hacerlo, correspondería en Visual Basic 2005 al siguiente código fuente:
For I As Integer = 0 To bucle Me.TextBox1.Text &= «Elemento « & I & vbCrLf Next |
2) Iteramos una cadena de texto dentro de una variable definida como String para volcarla posteriormente sobre el control TextBox. En código Visual Basic 2005, este ejemplo quedaría de la siguiente forma:
Dim cadena As String = «» For I As Integer = 0 To bucle cadena &= «Elemento « & I & vbCrLf Next Me.TextBox1.Text = cadena |
3) Iteramos una cadena de texto dentro de un objeto System.Text.StringBuilder, para finalmente volcar el resultado en el control TextBox. El código en Visual Basic 2005 de esta iteración es el que se indica a continuación:
Dim cadena As New System.Text.StringBuilder For I As Integer = 0 To bucle cadena.Append(«Elemento « & I & vbCrLf) Next Me.TextBox1.Text = cadena.ToString() |
Si atendemos a las líneas de código, parece más claro el primer supuesto. Incluso tiene menos líneas de código, por lo que incluso podríamos llegar a pensar, que a la hora de mantener la aplicación y supuesto que tenemos más de una acción de iteración como esta, puede resultar mejor opción. Además tardamos menos tiempo en escribirla, así que debe ser una buena alternativa.
Por contra, el segundo y tercer supuesto, tiene un número muy similar de líneas de código, pero el segundo parece un poco más claro que el tercero, poco más la verdad, pero parece que es más claro porque es posible que estemos más habituados a usar una concatenación de cadenas utilizando una variable String. Aún y así, es la forma natural que muchos programadores suelen utilizar, así que la familiaridad es clara.
El tercer supuesto (StringBuilder), parte inicialmente con la peor nota, pero a lo mejor es la opción que deberíamos seleccionar. Al menos, es la que menos conocemos, así que igual nos soprende y es una de las opciones que deberíamos tener en cuenta (la duda siempre existe y debe existir para un informático).
Así que vamos a estudiar estos tres casos y analizaremos su comporamiento en iteraciones con pocos y muchos elementos.
Ejecutando los supuestos
Una vez que hemos preparado los supuestos y los hemos analizado someramente, pasaremos a ejecutarlos y estudiar sus resultados.
Vamos a ejecutar los supuestos estudiando diferentes iteraciones. Las iteraciones analizadas serán de 100, 250, 400, 500, 1000, 1500, 2000, 3000 y 5000 elementos. Posteriormente, habra unas iteraciones extras de 7500 y 10000 elementos para dos de los tres supuestos, pero eso lo explicaremos más adelante.
Para calcular los tiempos de las iteraciones, he utilizado el objeto Stopwatch, de esa manera obtendré unos tiempos muy precisos que nos ayudará a estudiar los resultados obtenidos.
Los resultados de los tiempos tomados para cada conjunto de iteraciones en cada uno de los supuestos, son los siguientes:
|
Examinando estos supuestos según una gráfica, los resultados quedarían de la siguiente manera:
Estudiando estos resultados, vemos que la concatenación de elementos de tipo cadena de texto en un control TextBox, consume sorprendentemente muchísimo más tiempo y recursos que la concatenación de elementos dentro de una variable String o utilizando StringBuilder, que según la gráfica su diferencia es casi inapreciable.
Para discernir las diferencias reales entre String y StringBuilder, vamos ahora a estudiar estos dos mecanismos, estudiando sus resultados iterando adicionalmente, 7500 y 10000 elementos. Los resultados de todas las iteraciones para estos dos supuestos, son los que se indican a continuación:
|
Los resultados de la comparación entre iteraciones con String y StringBuilder, son los que se indican en la siguiente gráfica:
Conclusiones
Las conclusiones tras realizar este estudio son las siguientes.
El uso de un objeto como un TextBox para iterar cadenas y volcar en este objeto los resultados no es óptimo. A mayor número de iteraciones, peor rendimiento en comparación con iteraciones menores. Existe no obstante una explicación lógica para comprender lo que sucede. El objeto TextBox necesita que se repinte los elementos del objeto cada vez que se inserta un elemento, por lo que si las iteraciones son grandes, las veces que repintamos el objeto son mayores, y como cada vez que repintamos tenemos que repintar todos sus elementos, el tiempo de demora es muy elevado como podemos observar en los tiempos tomados en la prueba.
Podemos iterar cadenas dentro de una variable tipo String y volcar su resultado a un control TextBox, pero pese a que su funcionamiento es bastante ágil con respecto a StringBuilder, su lentitud se empieza a encontrar a partir de iteraciones largas. Es ahí, con grandes iteraciones, dónde el rendimiento de concatenar cadenas dentro de una variable String queda patente. Aún y así, siempre es mucho más rápido y con grandes diferencias, que concatenar directamente las cadenas dentro del objeto TextBox.
StringBuilder es para iterar cadenas y volcar su resultado en un control TextBox, el comando recomendado. Con iteraciones grandes, su rendimiento empieza a quedar afectado, pero aún y así, es incluso en estos casos, la mejor opción mejorando progresivamente la opción de usar una variable String para concatenar cadenas.
Obviamente, todos estos resultados, son orientativos, pero dependen de varios factores como el hardware del equipo que ejecuta la prueba, etc. Aún y así, son resultados muy próximos al funcionamiento real de estas formas de trabajar.
12 Responsesso far
Muchas veces, cuando nos ponemos a escribir código como posesos, no nos damos cuenta de pequeños detalles,…
Interesante este articulo [;)]
Las alternativas a veces no son tan claras. Buena información
Muy ilustrativo y apropiado el análisis realizado.
Muy ilustrativo el articulo. Sabia que utilizar StringBuilders era mas eficiente para concatenar cadenas pero nunca me habia puesto a programar un ejemplo.
En mi opinion, para que quedara completo, faltaria el motivo de la diferencia de rendimiento en este tipo de uso entre string y stringbuilder.
Muchas veces, cuando nos ponemos a escribir código como posesos, no nos damos cuenta de pequeños detalles,…
Primeramente enhorabuena por el artículo, muy ilustrativo.
Con respecto a la diferencia de rendimiento entre el StringBuilder y String, con permiso del autor, intentaré explicarlo de manera muy simple. Es un tema de memoria dinámica.
Al crearse un objeto StringBuilder se dimensiona cierto espacio en memoria para albergar su contenido. Si el contenido real supera al previsto, se utilizan algorismos de redimensionamento muy eficientes. En cambio cuando hacemos concatenaciones con String, .NET tiene que ir creando a cada iteración el nuevo objeto concatenado.
El problema está en que las curvas de rendimiento se encuentran igualadas hasta cierto punto en el que el rendimiento del StringBuilder se dispara. Esto es así porque el tiempo empleado por StringBuilder para el manejo dinámico de la memoria penaliza el rendimiento final cuando el número de elementos es pequeño. Es por eso que podemos asumir como válida cualquiera de las dos alternativas cuando N es pequeño (por ejemplo, concatenando todas las partes que conforman una dirección postal).
Espero que sirva,
Saludos a todos y gracias por este blog, al que me estoy aficionando.
Miquel Parejo
pop@terra.es
como puedo agregar cadenas de caracter desde un boton a texbox
Excelente comentario
Excelente artículo, tomare esos pequeños detalles de hoy en adelante, gracias por compartir tus investigaciones 🙂
señor, cómo creo las gráficas del artículo ? salu2
Me parece fantastico tu block me sucedio un problema con unaos datos concatenados para base de datos mayores los jalo de una grilla pero es muy optimo con el stringbuilder. gracias por todo mis respetos para ti una gente que comparte los conocimientos siempre suele llegar lejos y sobre todo llega lejos espiritulamente