¿Cuál es la forma más eficiente de concatenar cadenas?
c#
.net
string
optimization
jimmij
fuente
fuente
StringBuilder
puede encontrar información más detallada sobre casos de uso aquí .String.Format
en los esteroides. Lo cual, en cuanto al rendimiento, es un poco más lento en una línea+
yString.Concat
, pero mucho mejor que eso, aunque más lento queStringBuilder
en varias llamadas. Hablando en términos prácticos, las diferencias de rendimiento son tales que, si tuviera que elegir solo una forma de concatenar, elegiría interpolaciones de cadenas usando$
... Si hay dos formas, luego agregueStringBuilder
a mi caja de herramientas. Con esas dos formas estás listo.String.Join
respuesta a continuación no hace+
justicia y es, prácticamente hablando, una mala manera de concatenar cadenas, pero es sorprendentemente rápido en cuanto a rendimiento. La respuesta por qué es interesante.String.Concat
yString.Join
ambos pueden actuar en matrices, pero enString.Join
realidad es más rápido. Aparentemente,String.Join
es bastante sofisticado y más optimizado queString.Concat
, en parte porque funciona de manera similar, yaStringBuilder
que calcula la longitud de la cadena primero y luego construye la cadena que se beneficia de este conocimiento utilizando UnSafeCharBuffer.String.Join
también requiere construir una matriz que parezca ineficiente para los recursos, ¿verdad? ... Resulta eso+
yString.Concat
construye matrices para sus componentes de todos modos. En consecuencia, la creación manual de una matriz y su alimentaciónString.Join
es comparativamente más rápida ... sin embargo,StringBuilder
aún tiene un rendimiento superiorString.Join
en casi todas las formas prácticas, mientras que$
es solo un poco más lenta y mucho más rápida en cadenas largas ... sin mencionar que es incómodo y feo de usarString.Join
si tiene para crear una matriz para ello en el acto.Respuestas:
El
StringBuilder.Append()
método es mucho mejor que usar el+
operador. Pero he descubierto que, al ejecutar 1000 concatenaciones o menos,String.Join()
es aún más eficiente queStringBuilder
.El único problema con
String.Join
es que tienes que concatenar las cadenas con un delimitador común.Editar: como señaló @ryanversaw , puede hacer el delimitador
string.Empty
.fuente
StringBuilder
tiene un enorme costo de inicio comparable, solo es eficiente cuando se usa con cadenas muy grandes o con muchas concatenaciones. No es trivial descubrir una situación determinada. Si el rendimiento es problemático, la creación de perfiles es su amigo (consulte ANTS).string.Concat
?Rico Mariani , el gurú de .NET Performance, tenía un artículo sobre este mismo tema. No es tan simple como uno podría sospechar. El consejo básico es este:
Otro artículo para respaldar esta afirmación proviene de Eric Lippert, donde describe las optimizaciones realizadas en
+
concatenaciones de una línea de manera detallada.fuente
Hay 6 tipos de concatenaciones de cadenas:
+
símbolo más ( ).string.Concat()
.string.Join()
.string.Format()
.string.Append()
.StringBuilder
.En un experimento, se ha demostrado que
string.Concat()
es la mejor manera de acercarse si las palabras son menos de 1000 (aproximadamente) y si las palabras son más de 1000, entoncesStringBuilder
deben usarse.Para obtener más información, consulte este sitio .
fuente
+
realidad era 3 milisegundos más rápido questring.Concat()
, aunque no he examinado la cantidad de cadenas requeridas antes de losstring.Concat()
atropellos+
.De Chinh Do: StringBuilder no siempre es más rápido :
Reglas de juego
Cuando concatene tres valores de cadena dinámica o menos, use la concatenación de cadena tradicional.
Cuando concatene más de tres valores de cadena dinámica, use
StringBuilder
.Cuando construya una cadena grande a partir de varios literales de cadena, use el
@
literal de cadena o el operador en línea +.La mayoría de las veces
StringBuilder
es su mejor apuesta, pero hay casos, como se muestra en esa publicación, que al menos debería pensar en cada situación.fuente
Si está operando en un bucle,
StringBuilder
es probablemente el camino a seguir; le ahorra la sobrecarga de crear nuevas cadenas regularmente. Sin embargo, en el código que solo se ejecutará una vez,String.Concat
probablemente esté bien.Sin embargo, Rico Mariani (gurú de la optimización .NET) realizó un cuestionario en el que afirmó al final que, en la mayoría de los casos, recomienda
String.Format
.fuente
Este es el método más rápido que he desarrollado durante una década para mi aplicación NLP a gran escala. Tengo variaciones para
IEnumerable<T>
y otros tipos de entrada, con y sin separadores de diferentes tipos (Char
,String
), pero aquí muestro el caso simple de concatenar todas las cadenas en una matriz en una sola cadena, sin separador. La última versión aquí está desarrollada y probada en C # 7 y .NET 4.7 .Hay dos claves para un mayor rendimiento; el primero es calcular previamente el tamaño total exacto requerido. Este paso es trivial cuando la entrada es una matriz como se muestra aquí. En
IEnumerable<T>
cambio, para el manejo , vale la pena reunir primero las cadenas en una matriz temporal para calcular ese total (la matriz se requiere para evitar llamarToString()
más de una vez por elemento, ya que técnicamente, dada la posibilidad de efectos secundarios, hacerlo podría cambiar la semántica esperada de una operación de 'unión de cadenas').A continuación, dado el tamaño total de asignación de la cadena final, el mayor impulso en el rendimiento se obtiene al construir la cadena de resultados en el lugar . Hacer esto requiere la técnica (quizás controvertida) de suspender temporalmente la inmutabilidad de un nuevo
String
que inicialmente se asigna lleno de ceros. Dejando a un lado cualquier controversia, sin embargo ...Código completo:
Debo mencionar que este código tiene una ligera modificación de lo que yo uso. En el original, llamo a la instrucción cpblk IL de C # para hacer la copia real. Por simplicidad y portabilidad en el código aquí, reemplacé eso con P / Invoke
memcpy
, como puede ver. Para obtener el máximo rendimiento en x64 ( pero quizás no en x86 ), puede utilizar el método cpblk .fuente
string.Join
hace todas estas cosas ya por ti. No hay necesidad de escribirlo usted mismo. Calcula el tamaño de la cadena final, construye una cadena de ese tamaño y luego escribe en la matriz de caracteres subyacente. Incluso tiene la ventaja de usar nombres de variables legibles en el proceso.String.Join
puede ser eficiente. Como indiqué en la introducción, el código aquí es solo la ilustración más simple de una familia de funciones que uso para escenarios queString.Join
no maneja (como la optimización para elChar
separador) o no manejó en versiones anteriores de .NET. Supongo que no debería haber escogido esto para el ejemplo más simple, ya que es un caso queString.Join
ya se maneja bien, aunque con la "ineficiencia", probablemente inconmensurable, de procesar un separador vacío, a saber.String.Empty
.Concat
, que también lo hace correctamente. De cualquier manera, no necesita escribir el código usted mismo.String.Join
mi código con este arnés de prueba . Para 10 millones de operaciones de concatenación aleatoria de hasta 100 cadenas de tamaño de palabra cada una, el código que se muestra arriba es consistentemente un 34% más rápido queString.Join
en la versión de lanzamiento x64 con .NET 4.7 . Dado que el OP solicita explícitamente el método "más eficiente", el resultado sugiere que se aplica mi respuesta. Si esto responde a sus inquietudes, lo invito a que reconsidere su voto negativo.De este artículo de MSDN :
Entonces, si confía en MSDN, vaya con StringBuilder si tiene que hacer más de 10 operaciones / concatenaciones de cadenas; de lo contrario, la cadena simple concat con '+' está bien.
fuente
También es importante señalar que debe usar el
+
operador si está concatenando literales de cadena .Cómo: Concatenar cadenas múltiples (Guía de programación de C #)
fuente
Además de las otras respuestas, tenga en cuenta que StringBuilder puede recibir una cantidad inicial de memoria para asignar .
Agregar repetidamente a un StringBuilder que no ha sido preasignado puede resultar en muchas asignaciones innecesarias al igual que concatenar repetidamente cadenas regulares.
Si sabe cuánto durará la cadena final, puede calcularla trivialmente o puede hacer una suposición educada sobre el caso común (asignar demasiado no es necesariamente algo malo), debe proporcionar esta información al constructor o al Capacidad de propiedad. Especialmente cuando se ejecutan pruebas de rendimiento para comparar StringBuilder con otros métodos como String.Concat, que hacen lo mismo internamente. Cualquier prueba que vea en línea que no incluya la asignación previa de StringBuilder en sus comparaciones es incorrecta.
Si no puede adivinar el tamaño, probablemente esté escribiendo una función de utilidad que debería tener su propio argumento opcional para controlar la preasignación.
fuente
Lo siguiente puede ser una solución alternativa más para concatenar múltiples cadenas.
interpolación de cuerdas
fuente
String.Format
más legible y más fácil de trabajar. Benchmarking él, es ligeramente más lento que+
yString.Concat
en uno concatenaciones de línea, pero mucho mejor que ambos los que están en las llamadas repetitivas que hacenStringBuilder
menos necesaria.Lo más eficiente es usar StringBuilder, así:
@jonezy: String.Concat está bien si tienes un par de cosas pequeñas. Pero si está concatenando megabytes de datos, es probable que su programa se acumule.
fuente
Pruebe estas 2 piezas de código y encontrará la solución.
Vs
Encontrará que el primer código terminará realmente rápido y la memoria estará en una buena cantidad.
El segundo código tal vez la memoria estará bien, pero llevará más tiempo ... mucho más. Entonces, si tiene una aplicación para muchos usuarios y necesita velocidad, use la 1ra. Si tiene una aplicación para un usuario a corto plazo, tal vez pueda usar ambas o la segunda será más "natural" para los desarrolladores.
Salud.
fuente
Para solo dos cadenas, definitivamente no desea usar StringBuilder. Hay un umbral por encima del cual la sobrecarga de StringBuilder es menor que la sobrecarga de asignar varias cadenas.
Entonces, para más de 2-3 cadenas, use el código de DannySmurf . De lo contrario, solo use el operador +.
fuente
System.String es inmutable. Cuando modificamos el valor de una variable de cadena, se asigna una nueva memoria al nuevo valor y se libera la asignación de memoria anterior. System.StringBuilder fue diseñado para tener el concepto de una cadena mutable donde se pueden realizar una variedad de operaciones sin asignación de ubicación de memoria separada para la cadena modificada.
fuente
Otra solución:
dentro del bucle, use List en lugar de string.
Es muy muy rápido.
fuente
Realmente depende de su patrón de uso. Un punto de referencia detallado entre string.Join, string, Concat y string.Format se puede encontrar aquí: String.Format no es adecuado para el registro intensivo
(Esta es en realidad la misma respuesta que le di a esta pregunta)
fuente
Dependería del código. StringBuilder es más eficiente en general, pero si solo concatena unas pocas cadenas y lo hace todo en una línea, las optimizaciones de código probablemente se encargarán de usted. También es importante pensar en cómo se ve el código: para conjuntos más grandes StringBuilder facilitará la lectura, para los pequeños StringBuilder simplemente agregará desorden innecesario.
fuente