2008-09-29 5 views
30

Je connais bien les différentes façons de gérer le texte d'analyse pour plus d'informations. Pour analyser les entiers, par exemple, quel type de performance peut être attendu. Je me demande si quelqu'un connaît de bonnes statistiques à ce sujet. Je cherche des chiffres réels de quelqu'un qui a testé cela.Performances d'analyse (If, TryParse, Try-Catch)

Lequel de ces offre la meilleure performance dans quelles situations?

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

Il y a quelque temps, Jon Skeet a fait quelques repères pour ce genre de choses. Désolé, je n'ai pas de lien prêt - Peut-être que je suis sur google? –

Répondre

60

Toujours utiliser T.TryParse (string str, à la valeur T). Lancer des exceptions est coûteux et devrait être évité si vous pouvez gérer la situation a priori. L'utilisation d'un bloc try-catch pour «enregistrer» les performances (car votre débit de données incorrect est faible) constitue un abus du traitement des exceptions au détriment de la maintenabilité et de bonnes pratiques de codage. Suivez les bonnes pratiques de développement de l'ingénierie logicielle, écrivez vos cas de test, exécutez votre application, puis comparez et optimisez.

« Nous devons oublier les petits gains d'efficacité, disons environ 97% du temps. optimisation prématurée est la racine de tout le mal Pourtant, nous ne devons pas laisser passer nos opportunités dans cette critique de 3% » -Donald Knuth

Par conséquent, vous assignez, arbitrairement comme des crédits de carbone, que les performances de try-catch est pire et que la performance de TryParse est mieux. Seulement après avoir exécuté notre application et déterminé que nous avons une sorte de ralentissement w.r.t. l'analyse des chaînes serait même envisager d'utiliser autre chose que TryParse.

(edit: car il semble que la question voulait données de temps pour aller avec de bons conseils, voici les données temporelles demandées)

fois pour différents taux d'échec sur 10.000 entrées de l'utilisateur (pour les non-croyants) :

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

Aristote n'aurait jamais eu les mains sales en faisant une expérience. Honte honte. Vous devez affirmer quelque chose comme évidemment vrai. C'est la façon d'internet !!! –

+0

@chris: J'ai été réduit pour une raison quelconque ... Je suppose que la vérité fait mal. – user7116

+0

Merci d'avoir fait le benchmark quickie, même si la version try-catch est fausse d'être avec le fait que TryParse() soit plus rapide ne devrait même pas être prouvé ... –

6

Try-Catch sera toujours le plus lent. TryParse sera plus rapide.

L'IF et TryParse sont les mêmes.

+5

Pour être complètement clair, Try-Catch ne sera plus lent que si l'analyse échoue; ne pas lancer/attraper une exception ne coûte rien. – technophile

+0

Oui, une partie de la raison pour laquelle je posais la question est parce que je me demande quel est le coût de faire le bloc try-catch contre peut-être ne rien faire du tout. –

+1

Si l'erreur est peu probable, quel type de performance peut-on attendre? C'est pourquoi j'ai demandé quelques statistiques à ce sujet et pas seulement "Celui-ci est plus rapide" –

-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. 

La gestion des exceptions est relativement coûteuse, afin d'éviter si vous le pouvez.

En particulier, de mauvaises entrées sont à prévoir, pas exceptionnelles, donc vous ne devriez pas les utiliser dans cette situation.

(. Bien avant TryParse, il est peut-être la meilleure option)

+0

En ce qui concerne les options 1 et 4: Le PO essaie vraiment de déterminer si le coût du lancer est négligeable lorsque la possibilité de lancer est négligeable (il dit 0,0001%). Les options 2 et 3 sont vraiment la même chose. TryParse, dans les coulisses, fait exactement ce que l'option 2 fait, en supposant que l'option 2 n'ouvre pas sqlconnections ou quelque chose de bizarre. Enfin, l'option 3 vous n'avez jamais à vérifier null. Si vous allez ajouter un chèque, il vous suffit de vérifier le retour de l'essai. Donc, alors qu'à ce stade vous avez un score élevé et que vous savez probablement tout cela, je pense qu'il faut ajouter la clarté de la raison pour laquelle cette vieille réponse a -2 – Suamere

+0

What TryParse does: http://referencesource.microsoft.com/ # mscorlib/system/int32.cs, 325507e509229dbc – Suamere