2009-12-16 10 views
9

Durante el desarrollo de mi solicitud me encontré con algunas cosas comparación aquí fue todo:Cuál es la comparación rápida: Convert.ToInt32 (stringValue) == == intValue o stringValue intValue.ToString()

string str = "12345"; 
    int j = 12345; 
    if (str == j.ToString()) 
    { 
     //do my logic 
    } 

estaba pensando que el material anterior también se puede hacer con:

string str = "12345"; 
    int j = 12345; 
    if (Convert.ToInt32(str) == j) 
    { 
     //do my logic 
    } 

Así que he desarrollado un código de ejemplo para probar en términos de rendimiento cuál es mejor

 var iterationCount = 1000000; 
     var watch = new Stopwatch(); 
     watch.Start(); 
     string str = "12345"; 
     int j = 12345; 
     for (var i = 0; i < iterationCount; i++) 
     { 
      if (str == j.ToString()) 
      { 
       //do my logic 
      } 
     } 
     watch.Stop(); 

Y segunda:

var iterationCount = 1000000; 
    var watch = new Stopwatch(); 
    watch.Start(); 
    string str = "12345"; 
    int j = 12345; 
    for (var i = 0; i < iterationCount; i++) 
    { 
     if (Convert.ToInt32(str) == j) 
     { 
      //do my logic 
     } 
    } 
    watch.Stop(); 

En la ejecución de los dos ensayos anteriores que encontré las pruebas anteriores estaban dando casi el mismo tiempo transcurrido. Me gustaría discutir cuál es el mejor enfoque? ¿Y hay algún otro enfoque mejor que dos por encima de dos?

Respuesta

12

Su prueba es fundamentalmente defectuosa. El compilador y el tiempo de ejecución son bestias realmente inteligentes y optimizarán el código tanto en tiempo de compilación como de ejecución (JIT-ing). En este caso, usted está haciendo lo mismo cada vez que será detectado por el compilador y optimizado, por lo que el tiempo será similar para cada método.

Pruebe esta versión (sólo tengo .Net 2.0, por lo tanto los ligeros cambios):

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Diagnostics; 

namespace ToStringTest 
{ 
    class Program 
    { 
     const int 
      iterationCount = 1000000; 

     static TimeSpan Test1() 
     { 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      string str = "12345"; 
      int j = 12345; 
      for (int i = 0; i < iterationCount; i++) 
      { 
       if (str == i.ToString()) 
       { 
        //do my logic 
       } 
      } 
      watch.Stop(); 
      return watch.Elapsed; 
     } 

     static TimeSpan Test2() 
     { 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      string str = "12345"; 
      int j = 12345; 
      for (int i = 0; i < iterationCount; i++) 
      { 
       if (Convert.ToInt32(i) == j) 
       { 
        //do my logic 
       } 
      } 
      watch.Stop(); 
      return watch.Elapsed; 
     } 

     static void Main(string[] args) 
     { 
      Console.WriteLine("ToString = " + Test1().TotalMilliseconds); 
      Console.WriteLine("Convert = " + Test2().TotalMilliseconds); 
     } 
    } 
} 

y verá una gran diferencia. Uno es dos órdenes de magnitud más rápido que el otro. Y realmente es obvio cuál es.

Necesita saber qué hacen las distintas operaciones para saber cuál es fundamentalmente más rápido.

la conversión de una cadena a un int requiere lo siguiente:

total = 0 
for each character in string 
    total = total * 10 + value of charater 

y el ToString requiere:

string = "" 
while value != 0 
    string.AddToFront value % 10 
    value /= 10 

La multiplicación es mucho más fácil y más rápido, para una CPU que hacer que la división. Dada la elección de un algoritmo con muchas multiplicaciones frente a un algoritmo con muchas divisiones, siempre opte por lo primero ya que siempre será más rápido.

Luego está la comparación, una comparación int - int es simple, cargue cada valor en un registro y compare - un par de instrucciones de la máquina y listo. Una comparación entre dos cadenas requiere probar cada carácter en las cadenas de a una por vez, en el ejemplo que le dio fue de 5 bytes (una int es probablemente de 4 bytes) a la que accede más memoria.

2

Si el rendimiento es casi idéntico, vaya con la versión que sea más legible.

Personalmente, encuentro que el enfoque .ToString() es más fácil de entender y menos propenso a posibles problemas de transmisión que el otro enfoque.

6

Prefiero i.ToString() == str ya que nada garantiza que Convert.ToInt32(str) no falla.

+3

Si "000123"! = 123, esto es definitivamente mejor. –

3

Sí, muestra la lógica de su dominio como dentro de su ciclo de creación de perfiles, por lo que no estaba probando la diferencia de tiempo entre las versiones Convert y ToString de su código; estaba probando el tiempo combinado de la conversión más la ejecución de su lógica comercial. Si su lógica comercial es lenta y domina el tiempo de conversión, por supuesto verá el mismo tiempo en cada versión.

Ahora, con eso fuera del camino, incluso preocupándose por esto hasta que sepa que es un cuello de botella de rendimiento es una optimización prematura. En particular, si la ejecución de su lógica de dominio domina el tiempo de conversión, la diferencia entre los dos nunca importará. Por lo tanto, elija el que sea más legible.

Ahora, en cuanto a qué versión usar: debe comenzar especificando exactamente lo que está probando. ¿Cuáles son tus entradas? ¿Será "007" alguna vez una entrada? ¿Es "007" diferente del número entero 7? Es "1,024" alguna vez va a ser una entrada? ¿Hay problemas de localización?

+0

No probé con lógica de dominio dentro de mi perfil, solo fue un comentario escrito dentro de él, como lo he mostrado. – Raghav

+0

Muestra '// do my logic'. Todos interpretarán eso mientras haces tu lógica pero no quieres darnos los detalles, no es que comente la lógica. Para dejar en claro, sería mejor escribir la prueba como 'bool b = Convertir.ToInt32 (str) == j; 'etc. – jason

+0

@Raghav Khunger: Además, aunque hayas probado el rendimiento de los dos métodos sin ejecutar tu lógica de dominio, mi punto sigue en pie: no te preocupes hasta que sepas que es un cuello de botella de rendimiento. En su lugar, especifique completamente lo que está tratando de implementar y escriba el código de mantenimiento más legible que hace el trabajo. – jason

0

Bueno, para empezar, el primero que convierta el int en una cadena no arrojará un error si la cadena con la que se compara el int no es convertible a un int.

Si realiza muchas pruebas en una conversión por lotes a una cadena, se eliminará el problema de posibles excepciones debido a errores de conversión. Plantear excepciones lleva tiempo y ralentizaría la segunda prueba.

13

El rendimiento no debería ser lo único que importa.

Debe preguntar si desea comparar el valor real o solo la representación del número.

Tome el siguiente ejemplo: ¿"00001" es igual a 1? Si desea convertir la cadena a int usando Int.TryParse en combinación y luego compararlos.

Puede haber otras diferencias, también dependiendo de la configuración local. Tal vez el usuario se haya configurado para formatear números como "1,000,000"; si comparas esa cadena con 1000000.ToString(), el resultado sería falso.

2

La semántica es un poco diferente. "01" == 1.ToString() es falso, 1 == Convert.ToInt32("01") es true.

Si el análisis sintáctico puede salir mal (La cadena no es un número válido) entonces Int32.TryParse es más rápido que usar Convert.ToInt32().

0

bien, i mueve más un paso por delante y la prueba de esta manera:

int j = 123; 
    for (var i = 0; i < iterationCount; i++) 
    { 
     j.ToString(); 
    } 

segunda: str cadena = "123";

 for (var i = 0; i < iterationCount; i++) 
     { 
      Convert.ToInt32(str); 
     } 

En este caso, encontré que cada vez que el segundo uno funciona un poco mejor. En mi caso, el número sería como 100000 solamente y no en forma de 100.000. ¿Tus comentarios sobre esta prueba que hice en este post?

Cuestiones relacionadas