Lors d'une révision de code avec un employé de Microsoft, nous sommes tombés sur une grande section de code à l'intérieur d'un try{}
bloc. Elle et un représentant informatique ont suggéré que cela pouvait avoir des effets sur les performances du code. En fait, ils ont suggéré que la plupart du code devrait être en dehors des blocs try / catch, et que seules les sections importantes devraient être vérifiées. L'employé de Microsoft a ajouté et déclaré qu'un prochain livre blanc mettait en garde contre les blocages try / catch incorrects.
J'ai regardé autour de moi et j'ai découvert que cela pouvait affecter les optimisations , mais cela ne semble s'appliquer que lorsqu'une variable est partagée entre des étendues.
Je ne pose pas de question sur la maintenabilité du code, ni même sur la gestion des bonnes exceptions (le code en question doit sans doute être refacturé). Je ne fais pas non plus référence à l'utilisation d'exceptions pour le contrôle de flux, c'est clairement faux dans la plupart des cas. Ce sont des questions importantes (certaines sont plus importantes), mais pas le sujet ici.
Comment les blocs try / catch affectent-ils les performances lorsque des exceptions ne sont pas levées?
la source
Réponses:
Vérifie ça.
Production:
En millisecondes:
Nouveau code:
Nouveaux résultats:
la source
Après avoir vu toutes les statistiques pour avec try / catch et sans try / catch, la curiosité m'a forcé à regarder derrière pour voir ce qui est généré pour les deux cas. Voici le code:
C #:
MSIL:
C #:
MSIL:
Je ne suis pas un expert en IL mais nous pouvons voir qu'un objet d'exception local est créé sur la quatrième ligne
.locals init ([0] class [mscorlib]System.Exception ex)
après que les choses soient à peu près les mêmes que pour la méthode sans try / catch jusqu'à la ligne dix-septIL_0021: leave.s IL_002f
. Si une exception se produit, le contrôle passe à la ligne,IL_0025: ldloc.0
sinon nous passons à l'étiquetteIL_002d: leave.s IL_002f
et la fonction revient.Je peux supposer en toute sécurité que si aucune exception ne se produit, c'est la surcharge de la création de variables locales pour contenir
uniquement lesobjets d'exception et une instruction de saut.la source
Non. Si les optimisations triviales qu'un bloc try / finally empêche réellement ont un impact mesurable sur votre programme, vous ne devriez probablement pas utiliser .NET en premier lieu.
la source
Explication assez complète du modèle d'exception .NET.
Petits morceaux de performance de Rico Mariani: coût exceptionnel: quand lancer et quand ne pas lancer
Dmitriy Zaslavskiy:
la source
La structure est différente dans l'exemple de Ben M . Il sera étendu au-dessus de l'intérieur
for
boucle , ce qui entraînera une mauvaise comparaison entre les deux cas.Ce qui suit est plus précis pour la comparaison où tout le code à vérifier (y compris la déclaration de variable) se trouve dans le bloc Try / Catch:
Quand j'ai exécuté le code de test d'origine de Ben M , j'ai remarqué une différence dans la configuration du débogage et de la libération.
Cette version, j'ai remarqué une différence dans la version de débogage (en fait plus que l'autre version), mais il n'y avait aucune différence dans la version Release.
Conclusion :
Sur la base de ces tests, je pense que nous pouvons dire que Try / Catch ne n'ont un faible impact sur les performances.
EDIT:
J'ai essayé d'augmenter la valeur de la boucle de 10000000 à 1000000000, et j'ai exécuté à nouveau dans la version pour obtenir des différences dans la version, et le résultat était le suivant:
Vous voyez que le résultat est sans conséquence. Dans certains cas, la version utilisant Try / Catch est en fait plus rapide!
la source
try/catch
ici. Vous chronométrez 12 essais / captures entrant dans la section critique contre 10 millions de boucles. Le bruit de la boucle supprimera toute influence du try / catch. si au lieu de cela vous mettez le try / catch dans la boucle serrée, et comparez avec / sans, vous vous retrouveriez avec le coût du try / catch. (sans aucun doute, un tel codage n'est généralement pas une bonne pratique, mais si vous voulez chronométrer le temps système d'une construction, c'est comme ça que vous le faites). De nos jours, BenchmarkDotNet est l'outil incontournable pour des temporisations d'exécution fiables.J'ai testé l'impact réel d'un
try..catch
dans une boucle serrée, et il est trop petit en soi pour être un problème de performance dans une situation normale.Si la boucle fonctionne très peu (dans mon test, j'en ai fait un
x++
), vous pouvez mesurer l'impact de la gestion des exceptions. La boucle avec gestion des exceptions a pris environ dix fois plus de temps.Si la boucle fait un travail réel (dans mon test, j'ai appelé la méthode Int32.Parse), la gestion des exceptions a trop peu d'impact pour être mesurable. J'ai obtenu une différence beaucoup plus grande en échangeant l'ordre des boucles ...
la source
Les blocs try catch ont un impact négligeable sur les performances, mais le lancement d'exceptions peut être assez important, c'est probablement là que votre collègue a été confus.
la source
L'essai / capture a un impact sur les performances.
Mais ce n'est pas un impact énorme. la complexité try / catch est généralement O (1), tout comme une simple affectation, sauf quand ils sont placés dans une boucle. Vous devez donc les utiliser à bon escient.
Voici une référence sur les performances try / catch (n'explique pas la complexité de cela, mais c'est implicite). Jetez un coup d'œil à la section Lancer moins d'exceptions
la source
En théorie, un bloc try / catch n'aura aucun effet sur le comportement du code à moins qu'une exception ne se produise réellement. Il existe cependant de rares circonstances où l'existence d'un bloc try / catch peut avoir un effet majeur, et certaines rares, mais à peine obscures, où l'effet peut être perceptible. La raison en est que le code donné comme:
le compilateur peut être en mesure d'optimiser instruction1 sur la base du fait que l'instruction2 est garantie pour s'exécuter avant l'instruction3. Si le compilateur peut reconnaître que chose1 n'a pas d'effets secondaires et que chose2 n'utilise pas réellement x, il peut en toute sécurité omettre complètement chose1. Si [comme dans ce cas] thing1 était cher, cela pourrait être une optimisation majeure, bien que les cas où thing1 est cher sont également ceux que le compilateur serait le moins susceptible d'optimiser. Supposons que le code ait été modifié:
Il existe maintenant une séquence d'événements où l'instruction3 pourrait s'exécuter sans que l'instruction2 ait été exécutée. Même si rien dans le code de
thing2
ne pouvait lever d'exception, il serait possible qu'un autre thread puisse utiliser unInterlocked.CompareExchange
pour remarquer qu'il aq
été effacé et le définirThread.ResetAbort
, puis effectuer uneThread.Abort()
instruction before2 écrit sa valeur dansx
. Ensuite, lecatch
exécuteraitThread.ResetAbort()
[via déléguéq
], permettant à l'exécution de continuer avec instruction3. Une telle séquence d'événements serait bien sûr exceptionnellement improbable, mais un compilateur est nécessaire pour générer du code qui fonctionne conformément aux spécifications même lorsque de tels événements improbables se produisent.En général, le compilateur est beaucoup plus susceptible de remarquer des opportunités de laisser de simples bits de code que des bits complexes, et il serait donc rare qu'un essai / capture puisse affecter les performances beaucoup si des exceptions ne sont jamais levées. Pourtant, il existe des situations où l'existence d'un bloc try / catch peut empêcher des optimisations qui - sans le try / catch - auraient permis au code de s'exécuter plus rapidement.
la source
Bien que "la prévention soit meilleure que la manipulation ", dans une perspective de performance et d'efficacité, nous avons pu choisir le try-catch plutôt que la pré-varication. Considérez le code ci-dessous:
Voici le résultat:
la source
Voir la discussion sur l'implémentation try / catch pour une discussion sur la façon dont les blocs try / catch fonctionnent, et comment certaines implémentations ont une surcharge élevée, et certaines ont une surcharge nulle, lorsqu'aucune exception ne se produit. En particulier, je pense que l'implémentation de Windows 32 bits a des frais généraux élevés, et l'implémentation 64 bits ne l'est pas.
la source