Frage

Ich habe über verschachtelte try / catch-Anweisungen zu denken und begann über die Bedingungen, unter denen zu denken, wenn überhaupt, kann der JIT eine Optimierung oder Vereinfachung des kompilierten IL auszuführen.

Zur Veranschaulichung, die folgenden funktionell äquivalenten Darstellungen eines Exception-Handler.

// Nested try/catch
try
{
  try
  {
    try
    {
      foo();
    }
    catch(ExceptionTypeA) { }
  }
  catch(ExceptionTypeB) { }
}
catch(ExceptionTypeC) { }

// Linear try/catch
try
{
  foo();
}
catch(ExceptionTypeA) { }
catch(ExceptionTypeB) { }
catch(ExceptionTypeC) { }

Angenommen, es gibt keine zusätzliche Variablenreferenzen oder Funktionsaufrufe innerhalb des Stack-Frames der verschachtelten try-Anweisung kann die JIT Schluss, dass der Stack-Frames zu dem linearen Beispiel kollabiert werden kann?

Nun, wie etwa das folgende Beispiel?

void Try<TException>(Action action)
{
  try
  {
    action();
  }
  catch (TException) { }
}

void Main()
{
  Try<ExceptionC>(Try<ExceptionB>(Try<ExceptionA>(foo)));
}

Ich glaube nicht, gibt es eine Möglichkeit für den JIT der Delegierten Anrufungen Inline, so kann dieses Beispiel nicht auf den vorherigen reduziert werden. Doch in dem Fall von foo() Wurf ExceptionC geht diese Lösung schlechter durchführen, wenn auf das lineare Beispiel verglichen? Ich vermute, dass es zusätzliche Kosten, ist die Stack-Frames von den Delegierten Anrufungen abzureißen, obwohl die zusätzlichen Daten in den Rahmen enthalten ist minimal.

War es hilfreich?

Lösung

Es ist erwähnenswert, dass im ersten Fall sind sie nur funktionell gleichwertig, wenn man nichts in dem catch-Block tun. Andernfalls bedenken Sie:

try
{
    foo();
}
catch (IOException)
{
    throw new ArgumentException(); // Bubbles up to caller
}
catch (ArgumentException)
{
    Console.WriteLine("Caught");
}

vs

try
{
    try
    {
        foo();
    }
    catch (IOException)
    {
        throw new ArgumentException(); // Caught by other handler
    }
}
catch (ArgumentException)
{
    Console.WriteLine("Caught");
}

Jetzt in diesem Fall ist der Unterschied offensichtlich, aber wenn der catch-Block eine beliebige Methode aufruft, wie ist die JIT wissen sollte, was man geworfen werden? Die besten, vorsichtig zu sein.

Das läßt uns mit der Möglichkeit der JIT-Optimierungen für leere catch-Blöcke durchführen - eine Praxis, die stark an erster Stelle abgeraten. Ich will nicht die JIT-Zeit damit verbringen, schlechten Code zu erkennen und es ist sehr leicht schneller laufen -. Wenn in der Tat gibt es in erster Linie jeder Performance-Unterschied ist

Andere Tipps

Mein Verständnis von try / catch / finally Regionen in Bezug auf die Leistung ist, dass solche Regionen der regulären Ausführung von Code transparent sind. Das heißt, wenn Ihr Code keine Ausnahmen werfen zu fangen, dann sind die try / catch / finally Regionen NULL Auswirkungen auf die Ausführung von Code Leistung.

Wenn jedoch eine Ausnahme ausgelöst wird, beginnt die Laufzeit des Stapels von der Stelle, an der zu Fuß bis es angehoben wird, Tabellen von Metadaten zu überprüfen, ob die Website in Frage innerhalb einer der kritischen try-Blöcke enthalten ist. Wenn einer gefunden wird (und es hat einen qualifizierten Fangblock oder einen schließlich Block), dann der entsprechende Handler identifiziert und verzweigt die Ausführung zu diesem Punkt.

Der Prozess der Anhebung und Behandlung von Ausnahmen ist teuer aus Sicht der Leistung. Programmierer sollten keine Ausnahmen als eine Möglichkeit von Signal- oder Programmablauf in etwas anderes als außergewöhnliche Umstände Steuern (pun intended).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top