Beeinflusst Try-Catch wirklich die Programmleistung?
Heute habe ich mit TL über die Verwendung von Try-Catch gestritten, ob der gesamte Code dieser Methode in Try-Catch eingefügt werden soll, damit der Code schön aussieht Ich habe natürlich Einwände, aber ich habe den Implementierungsmechanismus von Try-Catch nicht eingehend untersucht und kann keinen überzeugenden Grund nennen. Heute habe ich eine .net-Try-Catch-Analyse im Internet gefunden und teile sie mit Ihnen In vielen Beiträgen wurde der Mechanismus von Try-Catch und seine Auswirkungen auf die Leistung analysiert.
Es gibt jedoch keine Hinweise darauf, dass Try-Catch zu viel Systemleistung verbraucht, insbesondere in einer Hosting-Umgebung. Ich erinnere mich, dass ein Internetnutzer im Garten StopWatch verwendet hat, um die Code-Laufzeitindikatoren von Try-Catch unter anderen Umständen im Vergleich zum Code ohne Try-Catch zu analysieren, und die Ergebnisse waren nicht sehr unterschiedlich.
Lassen Sie mich Try-Catch basierend auf IL analysieren.
● Mechanismusanalyse
Der grundlegende Ausnahmeerfassungs- und -verarbeitungsmechanismus in .Net wird durch try...catch...finally-Blöcke vervollständigt, die jeweils die Überwachung, Erfassung und Verarbeitung von Ausnahmen abschließen. Ein Try-Block kann null oder mehreren Catch-Blöcken entsprechen und kann null oder einem Final-Block entsprechen. Ein Versuch ohne Catch scheint jedoch bedeutungslos zu sein. Wenn der Versuch mehreren Catches entspricht, durchsucht die CLR den Code des Catch-Blocks von oben nach unten und filtert die entsprechende Ausnahme durch den Ausnahmefilter Wenn sie nicht gefunden wird, sucht die CLR nach passenden Ausnahmen entlang des Aufrufstapels zu höheren Ebenen. Wenn die entsprechende Ausnahme immer noch nicht oben im Stapel gefunden wird, wird der Code zu diesem Zeitpunkt ausgelöst Der Catch-Block wird nicht ausgeführt. Daher wird der Catch-Block, der dem Versuch am nächsten liegt, zuerst durchlaufen.
Wenn es den folgenden Code gibt:
try
{
Convert.ToInt32("Try");
}
Catch (FormatException ex1)
{
string CatchFor matException = "CatchFormatException";
}
Catch (NullReferenceException ex2)
{
String CatchNullReferenceException = "CatchNullReferenceException"; = "Finally";
}
Die entsprechende IL lautet wie folgt:
.method private hidebysig instance void Form1_Load(object sender,
class [mscorlib]System.EventArgs e) cil verwaltet
{
// Codegröße 53 (0x35)
.maxstack 1
.locals init ([0] class [mscorlib]System.FormatException ex1,
[1] string CatchFormatException,
[ 2] Klasse [mscorlib] System.NullReferenceException ex2,
[3] string CatchNullReferenceException,
[4] string Schließlich)
IL_0000: nop
IL_0001: nop
IL_0002: ldstr „Versuchen“
IL_0007: call int32 [mscorlib]System.Convert::ToInt32(string)
IL_000c: pop
IL_000d: nop
IL_000e: Leave.s IL_0026
IL_0010: stloc.0
IL_0011: nop
IL_0012: ldstr "CatchFormatException"
IL_0017: stloc.1
IL_0018: nop
IL_0019: Leave.s IL_0026
IL_001b: stloc.2
IL_001c: nop
IL_001d : ldstr "CatchNullReferenceException"
IL_0022: stloc.3
IL_0023: nop
IL_0024: Leave.s IL_0026
IL_0026: nop
IL_0027: Leave.s IL_0033
IL_0029: nop
IL_002A: LDSTR "Endlich"
IL_002F: Stloc.s Endlich
IL_0031: NOP
IL_0032: Endfinally
IL_0033: NOP
IL_0034: RET
. IL_0035:
// EX ception count 3
.try IL_0001 bis IL_0010 Catch [mscorlib]System.FormatException Handler IL_0010 bis IL_001b
.try IL_0001 bis IL_0010 Catch [mscorlib]System.NullReferenceException Handler IL_001b bis IL_0026
.try IL_0001 bis IL_0 029 schließlich Handler IL_0029 bis IL_0033
} // Ende der Methode Form1::Form1_Load
Die letzten Codezeilen zeigen, wie IL die Ausnahmebehandlung handhabt. Jedes Element in den letzten drei Zeilen wird als Ausnahmebehandlungsklausel bezeichnet. Der EHC bildet die Ausnahmebehandlungstabelle. Der EHT wird durch die ret-Return-Anweisung vom normalen Code getrennt.
Es ist ersichtlich, dass FormatException in EHT an erster Stelle steht.
Wenn der Code erfolgreich ausgeführt wird oder umgekehrt, durchläuft die CLR den EHT:
1. Wenn eine Ausnahme ausgelöst wird, findet die CLR den entsprechenden EHC anhand der „Adresse“ des Codes, der die Ausnahme auslöst (IL_0001 bis IL_0010 ist der Bereich des Erkennungscodes). EHCs und FormatException werden zuerst durchlaufen und sind ein geeigneter EHC.
2. Wenn die zurückgegebene Codeadresse innerhalb von IL_0001 bis IL_0029 liegt, wird auch der Final-Handler, d. h. der Code in IL_0029 bis IL_0033, ausgeführt, unabhängig davon, ob er aufgrund der erfolgreichen Ausführung des Codes zurückgegeben wird.
Tatsächlich wird die Traversierungsarbeit von „catch“ und „final“ separat ausgeführt. Wie oben erwähnt, durchläuft die CLR zunächst den entsprechenden „catch“-Block Dieser Prozess ist mindestens zweimal rekursiv, da der Compiler try...catch...finally von C# in zwei Verschachtelungsebenen in IL übersetzt.
Wenn der entsprechende Catch-Block nicht gefunden wird, führt die CLR natürlich direkt final aus und unterbricht dann sofort alle Threads. Der Code im Final-Block wird auf jeden Fall ausgeführt, unabhängig davon, ob try eine Ausnahme erkennt.
● Verbesserungsvorschläge
Daraus lässt sich schließen:
Wenn „Try-Catch“ verwendet wird und eine Ausnahme abgefangen wird, durchläuft die CLR lediglich die Catch-Elemente in der Ausnahmebehandlungstabelle; Wenn dann die Final-Elemente in der Ausnahmebehandlungstabelle erneut durchlaufen werden, wird fast die gesamte Zeit damit verbracht, die Ausnahmebehandlungstabelle zu durchlaufen. Wenn keine Ausnahme abgefangen wird, durchläuft die CLR nur die Final-Elemente in der Ausnahmebehandlungstabelle, und die erforderliche Zeit beträgt minimal.
Die Zeit, die zum Ausführen der entsprechenden Operation nach dem „Try-Catch“-Durchlauf benötigt wird, wird anhand Ihres spezifischen Codes bestimmt. „Try-Catch“ führt nur zur Überwachung und Auslösung, und dieser Teil der Codezeit sollte nicht gezählt werden Verbrauch „ausprobieren“ – „fangen“.
Daher können wir sowohl die Leistung als auch die Codeüberprüfung in Betracht ziehen. Die folgenden Richtlinien werden allgemein empfohlen:
1. Versuchen Sie, der CLR klare Ausnahmeinformationen zu geben und verwenden Sie keine Ausnahme, um Ausnahmen zu filtern.
2. Versuchen Sie, dies nicht zu tun Schreiben Sie try...catch in die Schleife
3. Probieren Sie so wenig Code wie möglich aus, verwenden Sie bei Bedarf mehrere Catch-Blöcke und schreiben Sie den Ausnahmetyp, der am wahrscheinlichsten ausgelöst wird, an die Position, die try am nächsten kommt
4. Don Deklarieren Sie nicht einfach ein Ausnahmeobjekt, ohne es zu behandeln. Dadurch wird die Länge der Ausnahmebehandlungstabelle vergeblich erhöht.
5. Verwenden Sie die „CLR-Ausnahmen“ des Leistungsindikator-Dienstprogramms, um Ausnahmen zu erkennen und entsprechend zu optimieren
6. Verwenden Sie den Try-Parse-Modus des Mitglieds. Wenn eine Ausnahme ausgelöst wird, ersetzen Sie diese durch „false“
Fazit: Obwohl Try-Catch einige Zeit in Anspruch nimmt, müssen Programmierer nicht darüber sprechen. Aufgrund der obigen Analyse ist es nicht so wichtig, dass „Try-Catch“ die Leistung beeinträchtigt " ist das Gleiche wie andere Codes, nur aus Leistungsgründen. Normale Verbraucher, aber für die Überprüfung des Code-Schreibens sollten Sie Ihr Bestes geben, um auf „Try-Catch“ zu achten.