2008-09-29 16 views
30

Sé mucho sobre las diferentes formas de manejar el análisis de texto para obtener información. Para analizar enteros, por ejemplo, qué tipo de rendimiento se puede esperar. Me pregunto si alguien sabe de alguna buena estadística sobre esto. Estoy buscando algunos números reales de alguien que ha probado esto.Rendimiento de análisis (si, TryParse, Try-Catch)

¿Cuál de estos ofrece el mejor rendimiento en qué situaciones?

Parse(...) // Crash if the case is extremely rare .0001% 

If (SomethingIsValid) // Check the value before parsing 
    Parse(...) 

TryParse(...) // Using TryParse 

try 
{ 
    Parse(...) 
} 
catch 
{ 
    // Catch any thrown exceptions 
} 
+0

Hace un tiempo Jon Skeet hizo algunos puntos de referencia para estas cosas. Lo siento, no tengo un enlace listo - ¿Tal vez ir a google? –

Respuesta

60

Siempre use T.TryParse (cadena str, disponibles Valor T). Lanzar excepciones es costoso y debe evitarse si puede manejar la situación a priori. El uso de un bloque try-catch para "guardar" el rendimiento (debido a que su velocidad de datos inválida es baja) es un abuso del manejo de excepciones a expensas de la facilidad de mantenimiento y las buenas prácticas de codificación. Siga las prácticas de desarrollo de ingeniería de software, escriba sus casos de prueba, ejecute su aplicación, luego compare y optimice.

"Debemos olvidarnos de pequeñas eficiencias, por ejemplo alrededor del 97% del tiempo:. optimización prematura es la raíz de todo mal Sin embargo, no hay que dejar pasar las oportunidades en que el 3% crítico" -Donald Knuth

por lo tanto, asignar, de manera arbitraria, como en los créditos de carbono, que el rendimiento de try-catch es peor y que el rendimiento de TryParse es mejor . Solo después de ejecutar nuestra aplicación y determinar que tenemos algún tipo de desaceleración w.r.t. El análisis sintáctico de cadena de caracteres consideraríamos usar cualquier cosa que no sea TryParse.

(edit: ya que parece que se deseaba, datos de temporización para ir con un buen consejo, aquí es los datos de tiempo solicitados)

el tiempo en distintos índices de fracaso de 10.000 entradas desde el usuario (para los creyentes) :

Failure Rate  Try-Catch   TryParse  Slowdown 
    0%   00:00:00.0131758 00:00:00.0120421  0.1 
10%   00:00:00.1540251 00:00:00.0087699  16.6 
20%   00:00:00.2833266 00:00:00.0105229  25.9 
30%   00:00:00.4462866 00:00:00.0091487  47.8 
40%   00:00:00.6951060 00:00:00.0108980  62.8 
50%   00:00:00.7567745 00:00:00.0087065  85.9 
60%   00:00:00.7090449 00:00:00.0083365  84.1 
70%   00:00:00.8179365 00:00:00.0088809  91.1 
80%   00:00:00.9468898 00:00:00.0088562 105.9 
90%   00:00:01.0411393 00:00:00.0081040 127.5 
100%   00:00:01.1488157 00:00:00.0078877 144.6 


/// <param name="errorRate">Rate of errors in user input</param> 
/// <returns>Total time taken</returns> 
public static TimeSpan TimeTryCatch(double errorRate, int seed, int count) 
{ 
    Stopwatch stopwatch = new Stopwatch(); 
    Random random = new Random(seed); 
    string bad_prefix = @"X"; 

    stopwatch.Start(); 
    for(int ii = 0; ii < count; ++ii) 
    { 
     string input = random.Next().ToString(); 
     if (random.NextDouble() < errorRate) 
     { 
      input = bad_prefix + input; 
     } 

     int value = 0; 
     try 
     { 
      value = Int32.Parse(input); 
     } 
     catch(FormatException) 
     { 
      value = -1; // we would do something here with a logger perhaps 
     } 
    } 
    stopwatch.Stop(); 

    return stopwatch.Elapsed; 
} 

/// <param name="errorRate">Rate of errors in user input</param> 
/// <returns>Total time taken</returns> 
public static TimeSpan TimeTryParse(double errorRate, int seed, int count) 
{ 
    Stopwatch stopwatch = new Stopwatch(); 
    Random random = new Random(seed); 
    string bad_prefix = @"X"; 

    stopwatch.Start(); 
    for(int ii = 0; ii < count; ++ii) 
    { 
     string input = random.Next().ToString(); 
     if (random.NextDouble() < errorRate) 
     { 
      input = bad_prefix + input; 
     } 

     int value = 0; 
     if (!Int32.TryParse(input, out value)) 
     { 
      value = -1; // we would do something here with a logger perhaps 
     } 
    } 
    stopwatch.Stop(); 

    return stopwatch.Elapsed; 
} 

public static void TimeStringParse() 
{ 
    double errorRate = 0.1; // 10% of the time our users mess up 
    int count = 10000; // 10000 entries by a user 

    TimeSpan trycatch = TimeTryCatch(errorRate, 1, count); 
    TimeSpan tryparse = TimeTryParse(errorRate, 1, count); 

    Console.WriteLine("trycatch: {0}", trycatch); 
    Console.WriteLine("tryparse: {0}", tryparse); 
} 
+2

Aristóteles nunca se habría ensuciado las manos realizando un experimento. Vergüenza, vergüenza. Debe afirmar algo como obviamente cierto. ¡Es la manera de Internet! –

+0

@chris: Me modifiqué por alguna razón ... Supongo que la verdad duele. – user7116

+0

Gracias por hacer el punto de referencia quickie, incluso si la versión try-catch está equivocada al estar así que el hecho de que TryParse() es más rápido ni siquiera necesita ser probado ... –

6

Try-Catch siempre será el más lento. TryParse será más rápido.

El IF y TryParse son iguales.

+5

Para ser completamente claro, Try-Catch solo será más lento si el análisis falla; no lanzar/atrapar una excepción no cuesta nada. – technophile

+0

Sí, parte de la razón por la que estaba preguntando es porque me pregunto cuál es el costo de hacer el bloqueo try-catch versus quizás no hacer nada en absoluto. –

+1

Si es poco probable que ocurra el error, ¿qué tipo de rendimiento se puede esperar? Es por eso que pedí algunas estadísticas sobre esto y no solo "Éste es más rápido" –

-3
Option 1: Will throw an exception on bad data. 
Option 2: SomethingIsValid() could be quite expensive - particularly if you are pre-checking a string for Integer parsability. 
Option 3: I like this. You need a null check afterwards, but it's pretty cheap. 
Option 4 is definitely the worst. 

El manejo de excepciones es relativamente caro, así que evita que si se puede.

En particular, las entradas son malas, no excepcionales, por lo que no debe utilizarlas para esta situación.

(. Aunque, antes de TryParse, puede haber sido la mejor opción)

+0

En cuanto a las opciones 1 y 4: El OP realmente está tratando de determinar si el costo de lanzamiento es insignificante cuando la posibilidad de lanzar es insignificante (dice 0.0001%). Las opciones 2 y 3 son realmente lo mismo. TryParse, entre bastidores, hace exactamente lo que hace la Opción 2, suponiendo que la Opción 2 no abre sqlconnections o algo raro. Por último, la opción 3 nunca tiene que verificar nulo. Si va a agregar un cheque, simplemente verifique la devolución del intento. Entonces, aunque en este momento tiene una puntuación alta y probablemente sepa todo esto, creo que debe agregarse como claridad el por qué esta respuesta anterior tiene -2 – Suamere

+0

Lo que TryParse hace: http://referencesource.microsoft.com/ # mscorlib/system/int32.cs, 325507e509229dbc – Suamere

Cuestiones relacionadas