Im Falle von Code, bei dem Sie vor dem Beenden einer Funktion eine Ressourcenbereinigung durchführen müssen, besteht ein wesentlicher Leistungsunterschied zwischen diesen beiden Methoden.
Bereinigen Sie die Ressource vor jeder return-Anweisung
void func() { login(); bool ret = dosomething(); if(ret == false) { logout(); return; } ret = dosomethingelse(); if(ret == false) { logout(); return; } dootherstuff(); logout(); }
Bereinigen Sie die Ressource in einem finally-Block
void func() { login(); try { bool ret = dosomething(); if(ret == false) return; ret = dosomethingelse(); if(ret == false) return; dootherstuff(); } finally { logout(); } }
Ich habe einige grundlegende Tests in Beispielprogrammen durchgeführt und es scheint keinen großen Unterschied zu geben. Ich bevorzuge das so sehr finally
- aber ich habe mich gefragt, ob es bei einem großen Projekt zu Leistungseinbußen kommen wird.
java
performance
efficiency
user93353
quelle
quelle
if(!cond)
, dann ist es Java, das mich dazu gebracht hat. In C ++ schreibe ich so Code sowohl für Boolesche als auch für andere Typen - dhint x;
if(!x)
. Da ich dies mit Java nur für verwenden darfbooleans
, habe ich die Verwendung vonif(cond)
&if(!cond)
in Java vollständig eingestellt .(someIntValue != 0)
als zu vergleichen, als Boolesche Werte zu bewerten. Das riecht für mich und ich überarbeite es sofort, wenn ich es in freier Wildbahn sehe.Antworten:
Wie in Wie langsam sind Java-Ausnahmen angegeben? man kann sehen, dass die Langsamkeit von
try {} catch {}
in der Ausnahmebedingung selbst liegt.Wenn Sie eine Ausnahme erstellen, wird der gesamte Aufrufstapel aus der Laufzeit abgerufen, und hier liegen die Kosten. Wenn Sie nicht eine Ausnahme zu schaffen, dann ist dies nur sehr leicht eine Erhöhung der Zeit.
In dem Beispiel in dieser Frage gibt es keine Ausnahmen, man würde keine Verlangsamung erwarten, wenn man sie erstellt - sie werden nicht erstellt. Stattdessen soll hier die
try {} finally {}
Freigabe von Ressourcen innerhalb des finally-Blocks behandelt werden.Um die Frage zu beantworten, nein, es gibt keinen wirklichen Laufzeitaufwand innerhalb eines
try {} finally {}
Struktur, die keine Ausnahmen verwendet (wie man sieht ist dies nicht ungewöhnlich). Was ist möglicherweise teuer ist die Wartungszeit , wenn man den Code liest und sieht diese nicht typischen Code - Stil und die Codierer haben ihren Geist zu umgehen , dass etwas anderes in diesem Verfahren nach dem passiert ,return
bevor sie an den vorherigen Anruf zurück.Wie bereits erwähnt, ist die Wartung ein Argument für beide Möglichkeiten. Für die Aufzeichnung, nach Abwägung, wäre meine Präferenz der endgültige Ansatz.
Berücksichtigen Sie die Wartungszeit, um jemandem eine neue Sprachstruktur beizubringen. Sehen
try {} finally {}
ist etwas, was man im Java-Code oft sieht und daher für die Leute verwirrend sein kann. Es gibt einen gewissen Grad an Wartungszeit, um etwas fortgeschrittenere Strukturen in Java zu erlernen, als die Leute mit dem Sehen vertraut sind.Der
finally {}
Block immer läuft . Und deshalb sollten Sie es verwenden. Berücksichtigen Sie auch die Wartungszeit für das Debuggen des nicht endgültigen Ansatzes, wenn jemand vergisst, sich zum richtigen Zeitpunkt abzumelden, oder es zur falschen Zeit aufruft oder vergisst, nach dem Aufruf zurückzukehren / zu beenden, sodass es zweimal aufgerufen wird. Es gibt so viele mögliche Fehler damit, dass die Verwendung vontry {} finally {}
unmöglich macht, zu haben.Wenn diese beiden Kosten abgewogen werden, ist es in der Wartungszeit teuer, das nicht zu verwenden
try {} finally {}
Ansatz . Während die Leute darüber streiten können, wie viele Bruchteil-Millisekunden oder zusätzliche JVM-Anweisungen dertry {} finally {}
Block mit der anderen Version verglichen wird, muss man auch die Stunden in Betracht ziehen, die für das Debuggen der weniger als idealen Methode zur Lösung der Ressourcendeallokation aufgewendet wurden.Schreiben Sie den wartbaren Code zuerst und vorzugsweise so, dass später keine Fehler mehr geschrieben werden.
quelle
/programming/299068/how-slow-are-java-exceptions
Die akzeptierte Antwort auf diese Frage zeigt, dass das Einschließen eines Funktionsaufrufs in einen Try-Catch-Block weniger als 5% gegenüber einem bloßen Funktionsaufruf kostet. Tatsächlich verursachte das Auslösen und Abfangen der Ausnahme, dass die Laufzeit mehr als das 66-fache des bloßen Funktionsaufrufs erreichte. Wenn Sie also erwarten, dass das Ausnahmedesign regelmäßig ausgelöst wird, würde ich versuchen, es zu vermeiden (in ordnungsgemäß profiliertem, leistungskritischem Code). Wenn die Ausnahmesituation jedoch selten ist, ist es keine große Sache.
quelle
Anstatt zu optimieren - überlegen Sie, was Ihr Code tut.
Das Hinzufügen des finally-Blocks ist eine andere Implementierung. Dies bedeutet, dass Sie sich bei jeder Ausnahme abmelden.
Insbesondere - wenn die Anmeldung eine Ausnahme auslöst, unterscheidet sich das Verhalten in Ihrer zweiten Funktion von Ihrem ersten.
Wenn An- und Abmeldung nicht zum Funktionsverhalten gehören, würde ich vorschlagen, dass die Methode eine Sache und eine Sache gut macht:
und sollte sich in einer Funktion befinden, die bereits in einem Kontext enthalten ist, der das Anmelden / Abmelden verwaltet, da diese sich grundlegend von dem zu unterscheiden scheinen, was Ihr Hauptcode tut.
Dein Beitrag ist mit Java markiert, mit dem ich nicht besonders vertraut bin, aber in .net würde ich dafür einen using-Block verwenden:
dh:
Der Anmeldekontext verfügt über eine Dispose-Methode, mit der die Ressourcen abgemeldet und bereinigt werden.
Edit: Ich habe die Frage nicht wirklich beantwortet!
Ich habe keine messbaren Beweise, aber ich würde nicht erwarten, dass dies teurer oder mit Sicherheit nicht signifikant genug ist, um eine vorzeitige Optimierung zu verdienen.
Ich werde den Rest meiner Antwort verlassen, da ich die Frage zwar nicht beantworte, sie aber für das OP hilfreich finde.
quelle
using
Konstrukt ähnelt , sofern die betreffende Ressource dieAutoCloseable
Schnittstelle implementiert .ret
Variable entfernen , die nur zweimal zugewiesen wird, um eine Zeile später überprüft zu werden. Mach esif (dosomething() == false) return;
.ret2 = doSomethingElse(ret1)
, aber das ist für die Frage nicht relevant, sodass sie entfernt wurde.if (dosomething() == false) ...
ist schlechter Code. Verwenden Sie die intuitivereif (!dosomething()) ...
Annahme: Sie entwickeln in C # -Code.
Die schnelle Antwort lautet, dass die Verwendung von try / finally-Blöcken keine signifikanten Leistungseinbußen zur Folge hat. Es gibt einen Leistungstreffer, wenn Sie Ausnahmen werfen und fangen.
Die längere Antwort ist, für sich selbst zu sehen. Wenn Sie sich den generierten zugrunde liegenden CIL-Code ansehen ( z. B. Red-Gate-Reflektor) , können Sie die generierten zugrunde liegenden CIL-Anweisungen und die Auswirkungen auf diese Weise anzeigen.
quelle
Wie bereits erwähnt, führt dieser Code zu unterschiedlichen Ergebnissen, wenn entweder
dosomethingelse
oderdootherstuff
eine Ausnahme eine Ausnahme .Und ja, jeder Funktionsaufruf kann eine Ausnahme auslösen, zumindest ein
StackOVerflowError
! Obwohl es selten möglich ist, diese korrekt zu behandeln (da jede aufgerufene Bereinigungsfunktion wahrscheinlich dasselbe Problem hat, ist es in einigen Fällen (wie zum Beispiel beim Implementieren von Sperren) entscheidend, diese auch korrekt zu behandeln ...quelle