Quelle est la lenteur des exceptions .NET?

143

Je ne veux pas de discussion sur quand et ne pas lancer d'exceptions. Je souhaite résoudre un problème simple. 99% du temps, l'argument pour ne pas lancer d'exceptions tourne autour de leur lenteur, tandis que l'autre partie affirme (avec un test de référence) que la vitesse n'est pas le problème. J'ai lu de nombreux blogs, articles et articles d'un côté ou de l'autre. Alors qu'est-ce que c'est?

Quelques liens des réponses: Skeet , Mariani , Brumme .

Goran
la source
13
il y a des mensonges, des mensonges et des repères. :)
gbjbaanb
Malheureusement, plusieurs réponses aux votes élevés ici ont manqué que la question se demande "à quel point les exceptions sont-elles lentes?", Et ont spécifiquement demandé d'éviter le sujet de la fréquence de leur utilisation. Une réponse simple à la question qui est réellement posée est ..... Sous Windows CLR, les exceptions sont 750 fois plus lentes que les valeurs de retour.
David Jeske

Réponses:

207

Je suis du côté "pas lent" - ou plus précisément "pas assez lent pour que cela vaille la peine de les éviter en utilisation normale". J'ai écrit deux courts articles à ce sujet. Il y a des critiques sur l'aspect de référence, qui sont principalement dues au fait que "dans la vraie vie, il y aurait plus de pile à parcourir, donc vous feriez sauter le cache, etc." - mais utiliser des codes d'erreur pour gravir la pile serait également faire sauter le cache, donc je ne vois pas cela comme un argument particulièrement bon.

Pour être clair, je ne soutiens pas l'utilisation d'exceptions là où elles ne sont pas logiques. Par exemple, int.TryParseest tout à fait approprié pour convertir les données d'un utilisateur. C'est approprié lors de la lecture d'un fichier généré par la machine, où l'échec signifie «Le fichier n'est pas dans le format qu'il est censé être, je ne veux vraiment pas essayer de gérer cela car je ne sais pas ce qui pourrait être faux. "

Lorsque j'utilise des exceptions dans «des circonstances raisonnables», je n'ai jamais vu une application dont les performances étaient considérablement affectées par des exceptions. Fondamentalement, les exceptions ne devraient pas se produire souvent, sauf si vous avez des problèmes d'exactitude importants, et si vous avez des problèmes d'exactitude importants, les performances ne sont pas le plus gros problème auquel vous êtes confronté.

Jon Skeet
la source
2
malheureusement, on dit aux gens que les exceptions sont gratuites, utilisez-les pour des fonctionnalités `` correctes '' triviales, elles devraient être utilisées comme vous le dites, lorsque les choses ont mal tourné - dans des circonstances `` exceptionnelles ''
gbjbaanb
4
Oui, les utilisateurs doivent certainement être conscients qu'il existe un coût de performance associé à l'utilisation inappropriée d'exceptions. Je pense juste que ce n'est pas un problème quand ils sont utilisés correctement :)
Jon Skeet
7
@PaulLockwood: Je dirais que si vous avez plus de 200 exceptions par seconde , vous abusez des exceptions. Ce n'est clairement pas un événement "exceptionnel" s'il se produit 200 fois par seconde. Notez la dernière phrase de la réponse: "Fondamentalement, les exceptions ne devraient pas se produire souvent, sauf si vous avez des problèmes d'exactitude importants, et si vous avez des problèmes d'exactitude importants, les performances ne sont pas le plus gros problème auquel vous êtes confronté."
Jon Skeet
4
@PaulLockwood: Ce que je veux dire, c'est que si vous avez plus de 200 exceptions par seconde, cela indique probablement déjà que vous abusez des exceptions. Cela ne me surprend pas que ce soit souvent le cas, mais cela signifie que l'aspect performance ne serait pas ma première préoccupation - l'abus d'exceptions le serait. Une fois que j'aurais supprimé toutes les utilisations inappropriées des exceptions, je ne m'attendrais pas à ce qu'elles jouent un rôle important dans les performances.
Jon Skeet
4
@DavidJeske: Vous avez manqué le point de la réponse. De toute évidence, lancer une exception est beaucoup plus lent que de renvoyer une valeur normale. Personne ne le soutient. La question est de savoir s'ils sont trop lents. Si vous êtes dans une situation appropriée pour lancer une exception et que cela pose un problème de performances, vous avez probablement de plus gros problèmes - car cela suggère qu'il y a énormément de problèmes avec votre système. Normalement, le problème est vraiment que vous utilisez des exceptions lorsqu'elles ne sont pas appropriées au départ.
Jon Skeet
31

Il y a la réponse définitive à cela de la part du gars qui les a mis en œuvre - Chris Brumme. Il a écrit un excellent article de blog sur le sujet (avertissement - c'est très long) (avertissement2 - c'est très bien écrit, si vous êtes un technicien, vous le lirez jusqu'à la fin et vous devrez ensuite rattraper vos heures après le travail :) )

Le résumé: ils sont lents. Ils sont implémentés en tant qu'exceptions Win32 SEH, donc certains passeront même la limite du processeur ring 0! De toute évidence, dans le monde réel, vous ferez beaucoup d'autres travaux, de sorte que l'exception étrange ne sera pas du tout remarquée, mais si vous les utilisez pour le flux du programme, attendez-vous à ce que votre application soit martelée. Ceci est un autre exemple de la machine marketing MS qui nous rend un mauvais service. Je me souviens d'un microsoftie nous disant comment ils ont encouru des frais généraux absolument nuls, ce qui est complet.

Chris donne une citation pertinente:

En fait, le CLR utilise en interne des exceptions, même dans les parties non gérées du moteur. Cependant, il existe un grave problème de performances à long terme avec des exceptions et cela doit être pris en compte dans votre décision.

gbjbaanb
la source
Je peux le mentionner dans les tests du monde réel, où un type Nullable provoque le déclenchement d'une exception à plusieurs reprises dans un "c'est un flux de programme normal", qui s'est soldé par des problèmes de performances significatifs. Rappelez-vous, les exceptions sont pour des cas exceptionnels, ne croyez personne qui dit le contraire ou vous vous retrouverez avec un fil de discussion github comme celui-là!
gbjbaanb
8

Je n'ai aucune idée de ce dont les gens parlent lorsqu'ils disent qu'ils sont lents seulement s'ils sont jetés.

EDIT: Si les exceptions ne sont pas lancées, cela signifie que vous faites une nouvelle exception () ou quelque chose du genre. Sinon, l'exception entraînera la suspension du thread et le parcours de la pile. Cela peut être correct dans des situations plus petites, mais dans les sites Web à fort trafic, le fait de s'appuyer sur des exceptions comme mécanisme de flux de travail ou de chemin d'exécution vous posera certainement des problèmes de performances. Les exceptions, en soi, ne sont pas mauvaises et sont utiles pour exprimer des conditions exceptionnelles

Le flux de travail d'exception dans une application .NET utilise des exceptions de première et de seconde chance. Pour toutes les exceptions, même si vous les attrapez et les gérez, l'objet d'exception est toujours créé et l'infrastructure doit toujours parcourir la pile pour rechercher un gestionnaire. Si vous attrapez et relancez, bien sûr, cela prendra plus de temps - vous allez obtenir une exception de première chance, l'attraper, la renvoyer, provoquant une autre exception de première chance, qui ne trouve alors pas de gestionnaire, ce qui provoque alors une exception de la seconde chance.

Les exceptions sont également des objets sur le tas - donc si vous lancez des tonnes d'exceptions, vous causez à la fois des problèmes de performances et de mémoire.

De plus, selon ma copie de "Performance Testing Microsoft .NET Web Applications" écrite par l'équipe ACE:

"La gestion des exceptions est coûteuse. L'exécution du thread impliqué est suspendue pendant que CLR se répète dans la pile d'appels à la recherche du bon gestionnaire d'exceptions, et lorsqu'il est trouvé, le gestionnaire d'exceptions et un certain nombre de blocs finally doivent tous avoir une chance de s'exécuter. avant que le traitement normal puisse être effectué. "

Ma propre expérience sur le terrain a montré que la réduction des exceptions améliorait considérablement les performances. Bien sûr, il y a d'autres choses que vous prenez en compte lors des tests de performances - par exemple, si vos E / S disque sont prises ou si vos requêtes sont dans les secondes, cela devrait être votre objectif. Mais trouver et supprimer des exceptions devrait être un élément essentiel de cette stratégie.

Cory Foy
la source
1
Rien de ce que vous avez écrit ne contredit l'affirmation selon laquelle les exceptions ne sont lentes que si elles sont lancées. Vous n'avez parlé que des situations où ils sont lancés. Lorsque vous avez «considérablement amélioré les performances» en supprimant les exceptions: 1) S'agit-il de conditions d'erreur réelles ou simplement d'une erreur utilisateur ?
Jon Skeet
2) Avez-vous fonctionné sous le débogueur ou non?
Jon Skeet
La seule chose que vous puissiez faire avec une exception si vous ne la lancez pas est de la créer en tant qu'objet, ce qui n'a pas de sens. Être sous le débogueur ou non n'a pas d'importance - ce sera toujours plus lent. Oui, il y a des hooks qui se produiront avec un débogueur attaché, mais c'est encore lent
Cory Foy
4
Je sais - je faisais partie de l'équipe Premier de MSFT. :) Disons simplement, beaucoup - des milliers de secondes dans certains cas extrêmes que nous avons vus. Rien de tel que de se connecter à un débogueur en direct et de voir les exceptions aussi vite que possible. Les ex sont lents - il en va de même pour la connexion à une base de données, donc vous le faites quand cela a du sens.
Cory Foy
5
Cory, je pense que le point de "lent seulement quand ils sont lancés" est que vous n'avez pas à vous soucier des performances à cause de la simple présence de blocs catch / finally. C'est-à-dire que ceux-ci ne provoquent pas en eux-mêmes une baisse des performances, seulement l'occurrence d'une instance d'exception réelle.
Ian Horwill
6

L'argument tel que je le comprends n'est pas que le fait de lancer des exceptions est mauvais, mais lent en soi. Au lieu de cela, il s'agit d'utiliser la construction throw / catch comme un moyen de première classe de contrôler la logique d'application normale, au lieu de constructions conditionnelles plus traditionnelles.

Souvent, dans la logique d'application normale, vous effectuez une boucle où la même action est répétée des milliers / millions de fois. Dans ce cas, avec un profilage très simple (voir la classe Stopwatch), vous pouvez voir par vous-même que lancer une exception au lieu de dire une simple instruction if peut s'avérer considérablement plus lent.

En fait, j'ai lu une fois que l'équipe .NET de Microsoft avait introduit les méthodes TryXXXXX dans .NET 2.0 pour de nombreux types de FCL de base spécifiquement parce que les clients se plaignaient que les performances de leurs applications étaient si lentes.

Il s'avère que dans de nombreux cas, cela était dû au fait que les clients tentaient de convertir le type de valeurs dans une boucle et que chaque tentative échouait. Une exception de conversion a été levée puis interceptée par un gestionnaire d'exceptions qui a ensuite avalé l'exception et continué la boucle.

Microsoft recommande maintenant que les méthodes TryXXX soient utilisées en particulier dans cette situation pour éviter de tels problèmes de performances possibles.

Je peux me tromper, mais il semble que vous ne soyez pas certain de la véracité des «benchmarks» que vous avez lus. Solution simple: essayez-le par vous-même.

Cendre
la source
Je pensais qu'internatlly ces fonctions "try" utilisent aussi des exceptions?
greg
1
Ces fonctions «Try» ne lèvent pas d'exceptions en interne pour un échec de l'analyse de la valeur d'entrée. Cependant, ils lèvent toujours des exceptions pour d'autres situations d'erreur, telles que ArgumentException.
Frêne
Je pense que cette réponse est plus proche du cœur du problème que toute autre. Dire «n'utiliser les exceptions que dans des circonstances raisonnables» ne répond pas vraiment à la question - la vraie idée est que l'utilisation d'exceptions C # pour le flux de contrôle est beaucoup plus lente que les constructions conditionnelles habituelles. Vous pourriez être pardonné de penser autrement. Dans OCaml, les exceptions sont plus ou moins un GOTO et la manière acceptée d'implémenter break lors de l'utilisation des fonctionnalités impératives. Dans mon cas particulier, le remplacement dans une boucle serrée de int.Parse () plus try / catch vs int.TryParse () a donné une amélioration significative des performances.
Hugh W
4

Mon serveur XMPP a considérablement augmenté sa vitesse (désolé, pas de chiffres réels, purement observationnel) après avoir constamment essayé de les empêcher de se produire (comme vérifier si une prise est connectée avant d'essayer de lire plus de données) et me donner des moyens de les éviter (les méthodes TryX mentionnées). C'était avec seulement environ 50 utilisateurs virtuels actifs (en conversation).

Jonathan C Dickinson
la source
3
Les chiffres seraient utiles, malheureusement: (Des choses comme les opérations de socket devraient largement dépasser les coûts d'exception, certainement quand il ne s'agit pas de débogage. Si jamais vous le comparez complètement, je serais vraiment intéressé de voir les résultats.
Jon Skeet
3

Juste pour ajouter ma propre expérience récente à cette discussion: conformément à la plupart de ce qui est écrit ci-dessus, j'ai trouvé que le lancement d'exceptions était extrêmement lent lorsqu'il était répété, même sans le débogueur en cours d'exécution. J'ai simplement augmenté les performances d'un grand programme que j'écris de 60% en modifiant environ cinq lignes de code: passer à un modèle de code de retour au lieu de lancer des exceptions. Certes, le code en question s'exécutait des milliers de fois et lançait potentiellement des milliers d'exceptions avant que je ne le modifie. Donc, je suis d'accord avec la déclaration ci-dessus: lancer des exceptions lorsque quelque chose d'important tourne mal, et non comme un moyen de contrôler le flux d'application dans des situations "attendues".

Ray Prisament
la source
2

Si vous les comparez aux codes de retour, ils sont lents comme l'enfer. Cependant, comme les affiches précédentes l'ont déclaré, vous ne voulez pas lancer le fonctionnement normal du programme, vous n'obtenez donc le coup de performance que lorsqu'un problème survient et dans la grande majorité des cas, les performances n'ont plus d'importance (car l'exception implique de toute façon un barrage routier).

Ils valent vraiment la peine d'être utilisés sur les codes d'erreur, les avantages sont vastes de l'OMI.

Quibblesome
la source
2

Je n'ai jamais eu de problème de performances avec des exceptions. J'utilise beaucoup les exceptions - je n'utilise jamais de codes de retour si je le peux. Ils sont une mauvaise pratique et, à mon avis, ils sentent le code de spaghetti.

Je pense que tout se résume à la façon dont vous utilisez les exceptions: si vous les utilisez comme des codes de retour (chaque appel de méthode dans la pile capture et relance) alors, oui, ils seront lents, car vous avez une surcharge à chaque capture / lancer.

Mais si vous lancez au bas de la pile et attrapez en haut (vous remplacez toute une chaîne de codes de retour par un lancer / attraper), toutes les opérations coûteuses sont effectuées une fois.

En fin de compte, ils constituent une fonctionnalité linguistique valide.

Juste pour prouver mon point

Veuillez exécuter le code sur ce lien (trop gros pour une réponse).

Résultats sur mon ordinateur:

marco@sklivvz:~/develop/test$ mono Exceptions.exe | grep PM
10/2/2008 2:53:32 PM
10/2/2008 2:53:42 PM
10/2/2008 2:53:52 PM

Les horodatages sont affichés au début, entre les codes de retour et les exceptions, à la fin. Cela prend le même temps dans les deux cas. Notez que vous devez compiler avec des optimisations.

Sklivvz
la source
2

Mais mono lève l'exception 10 fois plus vite que le mode autonome .net, et le mode autonome .net lance l'exception 60 fois plus vite que le mode débogueur .net. (Les machines de test ont le même modèle de CPU)

int c = 1000000;
int s = Environment.TickCount;
for (int i = 0; i < c; i++)
{
    try { throw new Exception(); }
    catch { }
}
int d = Environment.TickCount - s;

Console.WriteLine(d + "ms / " + c + " exceptions");
linquiser
la source
1

En mode de libération, la surcharge est minime.

À moins que vous n'utilisiez des exceptions pour le contrôle de flux (par exemple, des sorties non locales) de manière récursive, je doute que vous puissiez remarquer la différence.

leppie
la source
1

Sur le CLR Windows, pour une chaîne d'appels de profondeur 8, lever une exception est 750 fois plus lent que la vérification et la propagation d'une valeur de retour. (voir ci-dessous pour les benchmarks)

Ce coût élevé des exceptions est dû au fait que Windows CLR s'intègre à quelque chose appelé Gestion des exceptions structurée Windows . Cela permet aux exceptions d'être correctement interceptées et lancées dans différents environnements d'exécution et langages. Cependant, c'est très très lent.

Les exceptions dans l'environnement d'exécution Mono (sur n'importe quelle plate-forme) sont beaucoup plus rapides, car elles ne s'intègrent pas à SEH. Cependant, il y a une perte de fonctionnalité lors du passage d'exceptions sur plusieurs runtimes car il n'utilise rien comme SEH.

Voici les résultats abrégés de mon benchmark des exceptions par rapport aux valeurs de retour pour le CLR Windows.

baseline: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.25 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.5 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 0.75 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 1 (0), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0 (0), time elapsed 13.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.25 (249999), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.5 (499999), time elapsed 16.0009 ms
retval_error: recurse_depth 5, error_freqeuncy 0.75 (999999), time elapsed 16.001 ms
retval_error: recurse_depth 5, error_freqeuncy 1 (999999), time elapsed 16.0009 ms
retval_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 20.0011 ms
retval_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 21.0012 ms
retval_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 24.0013 ms
exception_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 31.0017 ms
exception_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 5607.3208     ms
exception_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 11172.639  ms
exception_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 22297.2753 ms
exception_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 22102.2641 ms

Et voici le code ..

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

public class TestIt {
    int value;

    public class TestException : Exception { } 

    public int getValue() {
        return value;
    }

    public void reset() {
        value = 0;
    }

    public bool baseline_null(bool shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            return shouldfail;
        } else {
            return baseline_null(shouldfail,recurse_depth-1);
        }
    }

    public bool retval_error(bool shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            if (shouldfail) {
                return false;
            } else {
                return true;
            }
        } else {
            bool nested_error = retval_error(shouldfail,recurse_depth-1);
            if (nested_error) {
                return true;
            } else {
                return false;
            }
        }
    }

    public void exception_error(bool shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            if (shouldfail) {
                throw new TestException();
            }
        } else {
            exception_error(shouldfail,recurse_depth-1);
        }

    }

    public static void Main(String[] args) {
        int i;
        long l;
        TestIt t = new TestIt();
        int failures;

        int ITERATION_COUNT = 1000000;


        // (0) baseline null workload
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            

                failures = 0;
                DateTime start_time = DateTime.Now;
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    bool shoulderror = (i % EXCEPTION_MOD) == 0;
                    t.baseline_null(shoulderror,recurse_depth);
                }
                double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
                Console.WriteLine(
                    String.Format(
                      "baseline: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
                        recurse_depth, exception_freq, failures,elapsed_time));
            }
        }


        // (1) retval_error
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            

                failures = 0;
                DateTime start_time = DateTime.Now;
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    bool shoulderror = (i % EXCEPTION_MOD) == 0;
                    if (!t.retval_error(shoulderror,recurse_depth)) {
                        failures++;
                    }
                }
                double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
                Console.WriteLine(
                    String.Format(
                      "retval_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
                        recurse_depth, exception_freq, failures,elapsed_time));
            }
        }

        // (2) exception_error
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            

                failures = 0;
                DateTime start_time = DateTime.Now;
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    bool shoulderror = (i % EXCEPTION_MOD) == 0;
                    try {
                        t.exception_error(shoulderror,recurse_depth);
                    } catch (TestException e) {
                        failures++;
                    }
                }
                double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
                Console.WriteLine(
                    String.Format(
                      "exception_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
                        recurse_depth, exception_freq, failures,elapsed_time));         }
        }
    }
}


}
David Jeske
la source
5
En plus de manquer le point de la question, veuillez ne pas utiliser DateTime.Now pour les repères - utilisez Chronomètre, qui est conçu pour mesurer le temps écoulé. Cela ne devrait pas être un problème ici car vous mesurez des périodes de temps raisonnablement longues, mais cela vaut la peine de prendre l'habitude.
Jon Skeet
Au contraire, la question est "les exceptions sont-elles lentes", point final. Il a spécifiquement demandé d'éviter le sujet du moment de lever des exceptions, car ce sujet obscurcit les faits. Quelles sont les performances des exceptions?
David Jeske
0

Une note rapide ici sur les performances associées à la capture des exceptions.

Lorsque le chemin d'exécution entre dans un bloc 'try', rien de magique ne se produit. Il n'y a pas d'instruction «try» et aucun coût associé à l'entrée ou à la sortie du bloc try. Les informations sur le bloc try sont stockées dans les métadonnées de la méthode, et ces métadonnées sont utilisées au moment de l'exécution chaque fois qu'une exception est déclenchée. Le moteur d'exécution parcourt la pile à la recherche du premier appel contenu dans un bloc try. Toute surcharge associée à la gestion des exceptions se produit uniquement lorsque des exceptions sont levées.

Drew Noakes
la source
1
Cependant, la présence d'exceptions peut avoir un impact sur l'optimisation - les méthodes avec des gestionnaires d'exceptions explicites sont plus difficiles à intégrer et la réorganisation des instructions est limitée par elles.
Eamon Nerbonne
-1

Lors de l'écriture de classes / fonctions que d'autres peuvent utiliser, il semble difficile de dire quand les exceptions sont appropriées. Il y a quelques parties utiles de BCL que j'ai dû abandonner et opter pour pinvoke car elles lancent des exceptions au lieu de renvoyer des erreurs. Dans certains cas, vous pouvez contourner ce problème, mais pour d'autres comme System.Management et Performance Counters, il existe des utilisations dans lesquelles vous devez effectuer des boucles dans lesquelles des exceptions sont fréquemment levées par BCL.

Si vous écrivez une bibliothèque et qu'il y a une faible possibilité que votre fonction soit utilisée dans une boucle et qu'il y ait un potentiel pour un grand nombre d'itérations, utilisez le modèle Try .. ou une autre façon d'exposer les erreurs à côté des exceptions. Et même dans ce cas, il est difficile de dire à quel point votre fonction sera appelée si elle est utilisée par de nombreux processus dans un environnement partagé.

Dans mon propre code, les exceptions ne sont lancées que lorsque les choses sont si exceptionnelles qu'il est nécessaire d'aller regarder la trace de la pile et de voir ce qui n'a pas fonctionné, puis de le réparer. J'ai donc pratiquement réécrit des parties de BCL pour utiliser la gestion des erreurs basée sur le modèle Try .. au lieu d'exceptions.

Lâche anonyme
la source
2
Cela ne semble pas correspondre à la déclaration de l'affiche « Je ne veux pas de discussion sur le moment de lancer des exceptions et de ne pas y avoir recours ».
hrbrmstr