2010-08-02 11 views
21

Cuando desarrollé en Java hace un par de años aprendí que es mejor agregar un carácter si tuviera un solo carácter en lugar de una cadena con un carácter porque la VM lo haría no tiene que hacer ninguna búsqueda en el valor de cadena en su grupo de cadenas interno.¿Hay alguna penalidad entre anexar cadena vs char en C#

string stringappend = "Hello " + name + "."; 
string charappend = "Hello " + name + '.'; // better? 

cuando empecé a programar en C# Nunca pensé en la posibilidad de que sería el mismo con su "máquina virtual". Me encontré con C# String Theory—String intern pool que dice que C# también tiene un grupo interno de cadenas (supongo que sería raro si no) así que mi pregunta es

¿Hay algún beneficio en agregar un carácter en lugar de una cadena cuando concatenando a una cadena con respecto a C# o es solo jibberish?

Editar: Haga caso omiso de StringBuilder y string.Format, estoy más interesado en por qué reemplazaría "." con '.' en codigo. Estoy muy consciente de esas clases y funciones.

+0

también se debe considerar el uso de 'StringBuilder' en lugar de' '+. – thelost

+2

Depende (TM). Si está desarrollando una aplicación para un entorno de escritorio, ni siquiera se moleste remotamente, la diferencia es completamente marginal. Si trabajas con un dispositivo integrado poco potente, entonces * * puede * valer la pena preocuparse. – Piskvor

+2

@Patrick: Probablemente deberías enfocar la pregunta hacia la búsqueda en lugar de char, de lo contrario, todos comenzarán sobre StringBuilder. –

Respuesta

16

Si se les da la opción, me gustaría pasar una string en lugar de un char al llamar System.String.Concat o el (equivalente) + operador.

Las únicas sobrecargas que veo para System.String.Concat toman todas las cadenas u objetos. Como un char no es una cadena, se elegiría la versión del objeto. Esto causaría que el char esté en caja. Después de que Concat verifique que la referencia del objeto no es nula, entonces llamaría a object.ToString en el char. Luego generaría la cadena temida de un solo carácter que se evitaba en primer lugar, antes de crear la nueva cadena concatenada.

Así que no veo cómo pasar un char va a ganar algo.

Tal vez alguien quiere ver la operación Concat en Reflector para ver si hay un manejo especial para el char?

ACTUALIZACIÓN

Mientras pensaba, esta prueba confirma que char es un poco más lento.

using System; 
using System.Diagnostics; 

namespace ConsoleApplication19 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      TimeSpan throwAwayString = StringTest(100); 
      TimeSpan throwAwayChar = CharTest(100); 
      TimeSpan realStringTime = StringTest(10000000); 
      TimeSpan realCharTime = CharTest(10000000); 
      Console.WriteLine("string time: {0}", realStringTime); 
      Console.WriteLine("char time: {0}", realCharTime); 
      Console.ReadLine(); 
     } 

     private static TimeSpan StringTest(int attemptCount) 
     { 
      Stopwatch sw = new Stopwatch(); 
      string concatResult = string.Empty; 
      sw.Start(); 
      for (int counter = 0; counter < attemptCount; counter++) 
       concatResult = counter.ToString() + "."; 
      sw.Stop(); 
      return sw.Elapsed; 
     } 

     private static TimeSpan CharTest(int attemptCount) 
     { 
      Stopwatch sw = new Stopwatch(); 
      string concatResult = string.Empty; 
      sw.Start(); 
      for (int counter = 0; counter < attemptCount; counter++) 
       concatResult = counter.ToString() + '.'; 
      sw.Stop(); 
      return sw.Elapsed; 
     } 
    } 
} 

Resultados:

string time: 00:00:02.1878399 
char time: 00:00:02.6671247 
+1

Así que estás diciendo que el '.' sería encasillado a "." de cualquier manera, lo que significa que mi pregunta es un poco vacía ...? Nunca pensé que el char estuviera en caja, pero tendría sentido. ¿El '+' se traduce a 'String.Concat' en C#? – Patrick

+0

@Patrick - Sí, la versión de cadena de + se convierte en cadena.Concat por el compilador. De hecho, a + b + c se convierte en string.Concat (a, b, c), lo cual es genial. Y no, '.' no se empaqueta en ".". Se encajona en un charro en caja. El problema es que (creo) se llamaría al método ToString() en la instancia encuadrada, que solo generaría "." de todas formas. Así que realmente terminas donde hubieras empezado si hubieras usado "." en primer lugar. –

+1

Ah, por supuesto, se empaqueta en Char ... * facepalm * Gracias por la aclaración y el ejemplo, no creo que me hubiera dado cuenta de esto. Entonces en C# uno debería preferir el uso de '". "' En lugar de ''.'', en oposición a Java, donde'' .'' sería el preferido. Gracias de nuevo – Patrick

0

Cada vez que concatenas cadenas usando el operador +, el tiempo de ejecución crea una nueva cadena, y para evitar eso, la práctica recomendada es el uso de la clase StringBuilder, que tiene el método Anexar. También puede usar AppendLine y AppendFormat. Si no desea utilizar StringBuilder, entonces se puede utilizar string.Format:

string str = string.Format("Hello {0}.", name); 
+1

Además del punto, la pregunta es acerca de la búsqueda de cadenas internas. –

+1

El interrogatorio de cuerdas es una gran amenaza aquí. –

+1

Además, 'string.Format' es más lento que' string.Concat'. –

0

Como las cadenas son inmutables tipos tanto requeriría la creación de una nueva instancia de una cadena antes de que el valor se devuelve de nuevo a usted.

Consideraría string.Concat(...) para un pequeño número de concatenaciones o la clase StringBuilder para muchas concatenaciones de cadenas.

12

Cuando desarrollé en Java hace un par de años aprendí que es mejor agregar un carácter si tenía un solo carácter en lugar de una cadena con un carácter porque la VM no tendría que hacer ninguna búsqueda en el valor de cadena en su grupo de cadenas interno.

Al añadir un char a un String es probable que sea ligeramente más rápido que añadiendo un 1 carácter String porque:

  • la operación append(char) no tiene que cargar la cadena length,
  • no tiene que cargar la referencia a la matriz characters,
  • no tiene que cargar y agregar la s Tring de start offset,
  • que no tiene que hacer una comprobación de límites en el índice de la matriz, y
  • que no tiene que incrementar y probar una variable de bucle.

Eche un vistazo al código fuente de Java para String y clases relacionadas. Puede que te sorprenda lo que sucede debajo del capó.

El grupo interno no tiene nada que ver con eso. El internamiento de literales de cadena ocurre solo una vez durante la carga de la clase.El internamiento de cadenas no literales solo ocurre si la aplicación explícitamente llama al String.intern().

+1

Buena explicación de por qué 'append (Char)' es más rápido que 'append (String)'. –

+0

Quizás no sea correcto en la práctica, pero eso fue lo que aprendí. ;-) Gracias por la explicación, entonces la desventaja de hecho no es que Java hizo una búsqueda, ¿pero esa cadena es "más grande" y más torpe que un personaje? Usted declara que el internamiento ocurre una vez, ¿eso significa que C# tiene un puntero a la cadena y simplemente lo reemplaza en "código" cuando la aplicación se ejecuta y la CLI sabe dónde reside la cadena en la memoria, por así decirlo? – Patrick

+1

@Patrick - sí, y sí. (Bueno al menos en el caso de Java/JVM ... No puedo hablar por C#/CLR.) –

3

Toda la concatenación de cadenas en .NET (con los operadores estándar, es decir, +) requiere que el tiempo de ejecución reserve suficiente memoria para una cadena completa nueva para contener los resultados de la concatenación. Esto se debe a que el tipo de cadena es inmutable.

Si realiza la concatenación de cadenas muchas veces (es decir, dentro de un bucle, etc.) sufrirá problemas de rendimiento (y eventualmente problemas de memoria si la cadena es suficientemente grande) ya que el tiempo de ejecución .NET necesita asignar y desasignar continuamente la memoria espacio para contener cada nueva cuerda.

Es probable que por esta razón piense (correctamente) que la concatenación excesiva de cadenas puede ser problemática. Tiene muy poco (si acaso) que ver con concatenar un char en lugar de un tipo de cadena.

La alternativa a esto es utilizar la clase StringBuilder en el espacio de nombres System.Text. Esta clase representa un objeto mutable similar a una cadena que se puede usar para concatenar cadenas sin la mayoría de los problemas de rendimiento resultantes. Esto se debe a que la clase StringBuilder reservará una cantidad específica de memoria para una cadena, y permitirá que las concatenaciones se agreguen al final de la cantidad de memoria reservada sin requerir una nueva copia completa de la cadena completa.

EDIT:

Con respecto a los detalles de las búsquedas de cuerda frente a las búsquedas de carbonilla, me prepararon rápidamente esta pequeña prueba:

class Program 
{ 
    static void Main(string[] args) 
    { 
     string stringtotal = ""; 
     string chartotal = ""; 
     Stopwatch stringconcat = new Stopwatch(); 
     Stopwatch charconcat = new Stopwatch(); 
     stringconcat.Start(); 
     for (int i = 0; i < 100000; i++) 
     { 
      stringtotal += "."; 
     } 
     stringconcat.Stop(); 
     charconcat.Start(); 
     for (int i = 0; i < 100000; i++) 
     { 
      chartotal += '.'; 
     } 
     charconcat.Stop(); 
     Console.WriteLine("String: " + stringconcat.Elapsed.ToString()); 
     Console.WriteLine("Char : " + charconcat.Elapsed.ToString()); 
     Console.ReadLine(); 
    } 
} 

se limita a la hora (con el alto rendimiento StopWatch clase) cuánto tiempo lleva concatenar 100000 puntos/períodos (.) de tipo cadena frente a 100000 puntos/períodos de tipo char. me encontré con esta prueba unas cuantas veces a lo largo para evitar que los resultados están sesgados de una carrera específica, sin embargo, cada vez que los resultados fueron similares a los siguientes:

String: 00:00:06.4606331 
Char : 00:00:06.4528073 

Por lo tanto, en el contexto de múltiples concatenaciones, Diría que hay muy poca diferencia (con toda probabilidad, no hay diferencia cuando se toman en cuenta las tolerancias estándar de ejecución de prueba) entre los dos.

+0

Esa prueba es quizás un poco irreal ya que terminas con una cadena que tiene un poco más de 100k de longitud. –

2

Estoy de acuerdo con lo que todos dicen sobre el uso de StringBuilder si está haciendo muchas concatenaciones de cadenas porque String es un tipo inmutable, pero no olvide que hay una sobrecarga al crear la clase StringBuilder también, así que tendrá que hacer una elección cuándo usar qué.

En uno de los libros Effect C# de Bill Wagner (o podría estar en los 3 de ellos ...), tocó esto también. En términos generales, si todo lo que necesita es agregar unos pocos fragmentos de cadena, string.Format es mejor, pero si necesita construir un valor de cadena grande en un bucle potencialmente grande, use StringBuilder.

4

Esto puede ser interesante: http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx

StringBuilder no son necesariamente más rápido que Cuerdas, que, como se dijo antes, depende . Depende de la configuración de la máquina, la memoria disponible frente a la potencia del procesador, la versión del marco y la configuración de la máquina.Su generador de perfiles es su mejor amigo en este caso :)

Atrás 2 Tema: Simplemente debe probar cuál es más rápido. Haz esa concatenación a bazillion veces y deja que tu profiler mire. Verás posibles diferencias.

0

No puedo hablar con C#, pero en Java, la principal ventaja no es la ganancia en tiempo de compilación sino la ganancia en tiempo de ejecución.

Sí, si utiliza un String, que en el momento de la compilación, Java tendrá que buscar el String en su grupo interno y posiblemente crear un nuevo objeto String. Pero esto solo ocurre una vez, en tiempo de compilación, cuando crea los archivos .class. El usuario nunca verá esto.

Lo que el usuario verá es que en tiempo de ejecución, si le da un carácter, el programa solo tiene que recuperar el carácter. Hecho. Si le da un String, primero debe recuperar el manejador del objeto String. Luego debe configurar un ciclo para recorrer todos los caracteres, recuperar el carácter, observar que no hay más caracteres y detenerse. No he observado el código de bytes generado, pero claramente es muchísimo más trabajo.

Cuestiones relacionadas