Performances d'analyse (If, TryParse, Try-Catch)
Question
Je connais bien les différentes manières de traiter le texte d'analyse pour en savoir plus. Pour l'analyse de nombres entiers, par exemple, quel type de performance peut être attendu. Je me demande si quelqu'un connaît de bonnes statistiques à ce sujet. Je suis à la recherche de vrais chiffres de la part de quelqu'un qui a testé cela.
Laquelle de celles-ci 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
}
La solution
Utilisez toujours T.TryParse (chaîne de caractères, valeur T) . Lancer des exceptions coûte cher et devrait être évité si vous pouvez gérer la situation a priori . Utilisation d'un bloc try-catch pour "enregistrer" sur les performances (car votre débit de données non valide est faible) est un abus de la gestion des exceptions au détriment de la maintenabilité et des bonnes pratiques de codage. Suivez les bonnes pratiques de développement de l’ingénierie logicielle, rédigez vos scénarios de test, exécutez votre application, THEN benchmark et optimisez.
"Nous devrions oublier les petites économies, disons environ 97% du temps: l'optimisation prématurée est la racine de tous les maux . Pourtant, nous ne devrions pas laisser passer nos opportunités dans ce domaine critique de 3% " -Donald Knuth
Par conséquent, vous indiquez, comme dans les crédits carbone, que les performances de try-catch sont pires et que les performances de TryParse sont meilleures . Ce n'est qu'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 envisagerait-elle d’utiliser autre chose que TryParse.
(éditer: étant donné que l'interrogateur a voulu que les données de synchronisation soient accompagnées de bons conseils, voici les données de synchronisation demandées)
Temps pour divers 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);
}
Autres conseils
Bien que je n'ai pas personnellement décrit les différentes manières, ce chapitre a:
Try-Catch sera toujours le plus lent. TryParse sera plus rapide.
Les valeurs IF et TryParse sont identiques.
Voici un autre représentant des différences de performances , et le fait avec quelques types de données différents pour voir combien (le cas échéant) ils affectent de manière inhérente les performances: int, bool et DateTime.
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, évitez-la donc si vous le pouvez.
En particulier, il faut s'attendre à des entrées incorrectes et non exceptionnelles, vous ne devez donc pas les utiliser pour cette situation.
(Bien qu'avant TryParse, c'était peut-être la meilleure option.)