Wie teuer sind Ausnahmen in C #?


73

Wie teuer sind Ausnahmen in C #? Es scheint, dass sie nicht unglaublich teuer sind, solange der Stapel nicht tief ist; Ich habe jedoch widersprüchliche Berichte gelesen.

Gibt es einen endgültigen Bericht, der nicht widerlegt wurde?


1
Ausnahmen, die nicht behandelt werden, sind nicht teuer. Sie können also try / block verwenden.
Kishore Kumar

@KishoreJangid - das Auslösen von Ausnahmen hat auch einen Overhead, selbst wenn sie nicht behandelt werden.
BornToCode

Antworten:


71

Jon Skeet hat im Januar 2006 Exceptions and Performance in .NET geschrieben

Welches wurde Ausnahmen und Performance Redux aktualisiert (danke @Gulzar)

Worauf Rico Mariani in Die wahren Kosten von .NET-Ausnahmen - Lösung einging


Siehe auch: Krzysztof Cwalina - Update der Designrichtlinien: Exception Throwing


Jon Skeet sagt im Grunde, "sie sind überhaupt nicht teuer", aber wie wir aus den anderen Antworten hier und anderswo im Internet sehen, stellen viele Leute fest, dass ihr C # -Code erheblich langsamer ist, wenn sie eine große Anzahl von Ausnahmen abfangen. Dies hat zwei Ursachen: 1) Einfache Beispiele zum Vergleichen der Ausführungszeit sind EINFACH, realer Code normalerweise nicht, und 2) Das Abfangen von Ausnahmen ist beim Debuggen viel teurer (da VS die Ausführung stoppen und Ihnen die Ausnahme anzeigen muss). In Anwendungen, in denen hunderttausende Male eine Schleife ausgeführt wird, summieren sich kleine Auswirkungen auf die Leistung.
Jspinella

Der Trend, den ich bei denen sehe, die sagen "mein Testcode zeigt, dass das Fangen von Ausnahmen SEHR teuer ist", ist, dass sie Tausende / Hunderttausende Male wiederholt werden. Wenn bei einer Iteration von 100.000 Objekten jeweils eine Ausnahme abgefangen wird und jeder Fang 1/33 ms "kostet" (gemäß der Antwort von Helge Klein), würde ich erwarten, dass das Ausfangen von Ausnahmen die Ausführungszeit um etwa 3 Sekunden verlängert. Da's Antwort deutet jedoch darauf hin, dass die Strafe viel höher als 1/33 ms ist (obwohl wir nicht wissen, wie viele Iterationen in seinem Beispiel vorhanden sind, sagt er, dass Ausnahmen nur in nur 15% der Fälle ausgelöst werden).
Jspinella

Dies ist eine alte Frage und eine alte Antwort, aber wir beantworten nur die Frage "Wie teuer sind Ausnahmen". Diese Frage ergibt sich unweigerlich aus der wohlbekannten Vorstellung, dass wir die Programmierung ausnahmsweise vermeiden wollen. Ausnahmen sollten für außergewöhnliche Umstände sein. Der Kern des Arguments ist, dass das Vermeiden von Ausnahmen im Allgemeinen der Leistung zugute kommt, aber Ausnahmen haben ihren Platz und sind nützlich, wenn sie richtig verwendet werden.
Robert Paulson

Es ist eine großartige Antwort, aber da die meisten Leute Ihre Antwort lesen und dann den Tab schließen und alle nützlichen und interessanten Antworten unten ignorieren, dachte ich, es lohnt sich hervorzuheben, was diese Antworten zu sagen haben.
Jspinella

20

Nachdem ich gelesen hatte, dass Ausnahmen in Bezug auf die Leistung kostspielig sind, habe ich ein einfaches Messprogramm zusammengestellt, das dem vor Jahren veröffentlichten von Jon Skeet sehr ähnlich ist . Ich erwähne dies hier hauptsächlich, um aktualisierte Zahlen bereitzustellen.

Das Programm benötigte weniger als 29914 Millisekunden, um eine Million Ausnahmen zu verarbeiten, was 33 Ausnahmen pro Millisekunde entspricht . Dies ist schnell genug, um Ausnahmen in den meisten Situationen zu einer praktikablen Alternative zu Rückkehrcodes zu machen.

Beachten Sie jedoch, dass mit Rückkehrcodes anstelle von Ausnahmen dasselbe Programm weniger als eine Millisekunde ausführt, was bedeutet, dass Ausnahmen mindestens 30.000 Mal langsamer sind als Rückkehrcodes . Wie von Rico Mariani betont, sind diese Zahlen auch Mindestzahlen. In der Praxis dauert das Werfen und Abfangen einer Ausnahme länger.

Gemessen auf einem Laptop mit Intel Core2 Duo T8100 bei 2,1 GHz mit .NET 4.0 im Release-Build, das nicht unter dem Debugger ausgeführt wird (was es viel langsamer machen würde).

Dies ist mein Testcode:

static void Main(string[] args)
{
    int iterations = 1000000;
    Console.WriteLine("Starting " + iterations.ToString() + " iterations...\n");

    var stopwatch = new Stopwatch();

    // Test exceptions
    stopwatch.Reset();
    stopwatch.Start();
    for (int i = 1; i <= iterations; i++)
    {
        try
        {
            TestExceptions();
        }
        catch (Exception)
        {
            // Do nothing
        }
    }
    stopwatch.Stop();
    Console.WriteLine("Exceptions: " + stopwatch.ElapsedMilliseconds.ToString() + " ms");

    // Test return codes
    stopwatch.Reset();
    stopwatch.Start();
    int retcode;
    for (int i = 1; i <= iterations; i++)
    {
        retcode = TestReturnCodes();
        if (retcode == 1)
        {
            // Do nothing
        }
    }
    stopwatch.Stop();
    Console.WriteLine("Return codes: " + stopwatch.ElapsedMilliseconds.ToString() + " ms");

    Console.WriteLine("\nFinished.");
    Console.ReadKey();
}

static void TestExceptions()
{
    throw new Exception("Failed");
}

static int TestReturnCodes()
{
    return 1;
}

2
Wie ich herausgefunden habe, sind sie in einer engen Spielschleife nicht lebensfähig. Ich habe versucht, mit meinen Index-Out-of-Bound-Checks faul zu sein :)
Mpen

Wie wäre es als Rückgabemechanismus für REST-Aufrufrückgabewerte? Angesichts des Overheads der Netzwerkverbindung selbst scheint das Auslösen einer Ausnahme mit einem eingebetteten HTTP-Statuscode ein sehr zuverlässiger, einheitlicher und relativ kostengünstiger Mechanismus für die Rückgabe von Werten zu sein, ganz zu schweigen von nützlicheren Informationen darüber, wo die Anforderung fehlgeschlagen ist . Es vereinfacht auch die Implementierung von Geschäftslogik drastisch, da Sie entweder erfolgreich zurückkehren oder informative, protokollierbare Ausnahmen auslösen.
Triynko

@mpen in gamedev (Es gibt Gespräche von Ubisoft, Naughty Dog usw.) Wenn es um C ++ geht, verwenden Sie in Ihrem Code überhaupt keine Ausnahmen. Was Sie tun, ist, dass Sie verwenden, assertwenn etwas Außergewöhnliches passiert. Die Fehlerbehandlung erfolgt mit Fehlercodes.
Konrad

Ich weiß nicht, ob dies für C # genauso funktioniert, zum Beispiel für Webentwickler.
Konrad

That is fast enough to make exceptions a viable alternative to return codes for most situations.Ich würde nicht sagen, dass ein Aufrufstapel mit einer Tiefe von 2-3 wirklich "die meisten Situationen " darstellt. Tiefere Call-Stacks sollten wahrscheinlich ebenfalls berücksichtigt werden.
Vector Sigma

17

Ich glaube , ich im Lager bin , dass , wenn die Leistung von Ausnahmen Auswirkungen auf Ihre Anwendung dann sind Sie werfen WAY zu viele von ihnen. Ausnahmen sollten für außergewöhnliche Bedingungen gelten, nicht als routinemäßige Fehlerbehandlung.

Trotzdem erinnere ich mich daran, wie Ausnahmen behandelt werden, indem ich im Wesentlichen den Stapel entlang gehe und eine catch-Anweisung finde, die dem Typ der ausgelösten Ausnahme entspricht. Die Leistung wird also am meisten davon beeinflusst, wie tief Sie vom Fang entfernt sind und wie viele Fangaussagen Sie haben.


4
@Colin Während ich Ihrer Aussage zustimme, schlängeln Sie sich vom Thema ab und Ihr Ton ist ein wenig predigend.
Robert Paulson

Und dann haben Sie ein Java-Camp, in dem Ausnahmen empfohlen werden.
Unbekannt

15
Wenn meine Meinung "predigen" ist, dann soll es so sein. Mein Punkt ist immer noch, dass Sie weniger Ausnahmen auslösen müssen, wenn Ausnahmen Ihre Leistung beeinträchtigen. Es ist nicht genau das, worum es bei der Frage von Chance geht, aber es ist mit Sicherheit ein Thema. Woher soll ich wissen, dass der Zufall meinen Standpunkt bereits berücksichtigt hat oder nicht?
Colin Burnett

18
Klingt für mich nicht predigend. Klingt genau so, wie Jon Skeet gesagt hat: "Wenn Sie jemals an einen Punkt gelangen, an dem Ausnahmen Ihre Leistung erheblich beeinträchtigen, haben Sie Probleme bei der Verwendung von Ausnahmen, die über die Leistung hinausgehen."
D'Arcy Rittich

Ausnahmen können zu Leistungsproblemen werden, selbst wenn es sich um außergewöhnliche Umstände handelt. Zum Beispiel eine Drittanbieter-API, auf die Sie angewiesen sind, während Ihrer Spitzenlast nicht mehr verfügbar zu sein. Ausnahmen sind angemessen (sogar unvermeidbar?), Aber selbst bei einer angemessenen Antwort kann die Leistung ein Problem sein, damit Sie korrekt reagieren können (z. B. benutzerdefinierte Fehlerseite), anstatt DOS zu sein (nicht geantwortet usw.).
Pinguat

4

Barebones-Ausnahmeobjekte in C # sind ziemlich leicht; Es ist normalerweise die Fähigkeit, eine zu kapseln InnerException, die es schwer macht, wenn der Objektbaum zu tief wird.

Was einen endgültigen Bericht betrifft, sind mir keine bekannt, obwohl ein flüchtiges dotTrace-Profil (oder ein anderer Profiler) für Speicherverbrauch und Geschwindigkeit ziemlich einfach zu erstellen sein wird.


4

In meinem Fall waren Ausnahmen sehr teuer. Ich habe das umgeschrieben:

public BlockTemplate this[int x,int y, int z]
{
    get
    {
        try
        {
            return Data.BlockTemplate[World[Center.X + x, Center.Y + y, Center.Z + z]];
        }
        catch(IndexOutOfRangeException e)
        {
            return Data.BlockTemplate[BlockType.Air];
        }
    }
}

Das mögen:

public BlockTemplate this[int x,int y, int z]
{
    get
    {
        int ix = Center.X + x;
        int iy = Center.Y + y;
        int iz = Center.Z + z;
        if (ix < 0 || ix >= World.GetLength(0)
            || iy < 0 || iy >= World.GetLength(1)
            || iz < 0 || iz >= World.GetLength(2)) 
            return Data.BlockTemplate[BlockType.Air];
        return Data.BlockTemplate[World[ix, iy, iz]];
    }
}

Und bemerkte eine gute Geschwindigkeitssteigerung von ca. 30 Sekunden. Diese Funktion wird beim Start mindestens 32K-mal aufgerufen. Code ist nicht so klar, was die Absicht ist, aber die Kosteneinsparungen waren enorm.


4
Ausnahmen, die nicht behandelt werden, sind nicht teuer.
Kishore Kumar

3

Ich habe meine eigenen Messungen durchgeführt, um herauszufinden, wie ernst die Auswirkungen auf Ausnahmen sind. Ich habe nicht versucht, die absolute Zeit für das Werfen / Fangen von Ausnahmen zu messen. Was mich am meisten interessiert hat, ist, wie viel langsamer eine Schleife wird, wenn in jedem Durchgang eine Ausnahme ausgelöst wird. Der Messcode sieht so aus

     for(; ; ) {
        iValue = Level1(iValue);
        lCounter += 1;
        if(DateTime.Now >= sFinish) break;
     }

vs.

     for(; ; ) {
        try {
           iValue = Level3Throw(iValue);
        }
        catch(InvalidOperationException) {
           iValue += 3;
        }
        lCounter += 1;
        if(DateTime.Now >= sFinish) break;
     }

Der Unterschied beträgt 20 mal. Das zweite Snippet ist 20-mal langsamer.


2

Der Leistungsausfall mit Ausnahmen scheint an dem Punkt zu sein, an dem das Ausnahmeobjekt generiert wird (wenn auch zu klein, um in 90% der Fälle Bedenken zu verursachen). Die Empfehlung ist daher Ihren Code profilieren - wenn Ausnahmen sind eine Leistungseinbußen verursachen, schreiben Sie eine neue High-perf - Methode , die keine Ausnahmen nicht verwendet. (Ein Beispiel, das mir in den Sinn kommt, wäre (TryParse wurde eingeführt, um Perf-Probleme mit Parse zu überwinden, das Ausnahmen verwendet).

Allerdings verursachen Ausnahmen in den meisten Fällen in den meisten Situationen keine signifikanten Leistungseinbußen. Daher soll die MS Design Guideline Fehler melden, indem Ausnahmen ausgelöst werden


Aber es tut sagen Ausnahmen sollten normalerweise nicht geworfen werden.. „Keine Ausnahmen für die normalen Ablauf der Steuerung verwenden mit Ausnahme von Systemausfällen, es in der Regel eine Möglichkeit , Code zu schreiben sein sollen , dass vermeiden Ausnahmen geworfen Zum Beispiel können Sie eine zur Verfügung stellen Möglichkeit, die Voraussetzungen vor dem Aufruf eines Mitglieds zu überprüfen, damit Benutzer Code schreiben können, der keine Ausnahmen auslöst. "
Andrew Aylett

1
@ Andrew: Richtig. Vielleicht hilft meine Antwort auf eine andere Frage dabei, meinen Stand zu klären . Stackoverflow.com/questions/859494 . Ausnahmen nur dann auslösen, wenn die Methode ihren Seinsgrund nicht erfüllen kann.
Gishu

Einverstanden :). Ich war mir einfach nicht sicher, ob "Fehler melden" klar genug war. Ich mag diese Richtlinien.
Andrew Aylett

2

Nur um meine persönliche Erfahrung zu vermitteln: Ich arbeite mit NewtonSoft an einem Programm, das JSON-Dateien analysiert und Daten daraus extrahiert.

Ich habe das umgeschrieben:

  • Option 1 mit Ausnahmen.
try
{
    name = rawPropWithChildren.Value["title"].ToString();
}
catch(System.NullReferenceException)
{
    name = rawPropWithChildren.Name;
}

Dazu:

  • Option 2 ohne Ausnahmen.
if(rawPropWithChildren.Value["title"] == null)
{
    name = rawPropWithChildren.Name;
}
else
{
    name = rawPropWithChildren.Value["title"].ToString();
}

Natürlich haben Sie nicht wirklich einen Kontext, um darüber zu urteilen, aber hier sind meine Ergebnisse:
( Im Debug-Modus )

  • Option 1 mit Ausnahmen. 38,50s

  • Option 2 mit Ausnahmen. 06.48s

Um ein wenig Kontext zu geben, arbeite ich mit Tausenden von JSON-Eigenschaften, die null sein können. Ausnahmen wurden viel zu oft ausgelöst, beispielsweise während 15% der Ausführungszeit. Nun, nicht wirklich präzise, ​​aber sie wurden zu oft geworfen. Ich wollte das beheben, also änderte ich meinen Code und verstand nicht, warum die Ausführungszeit so viel schneller war. Das lag an meiner schlechten Ausnahmebehandlung.

Was ich daraus gelernt habe: Ich muss Ausnahmen nur in bestimmten Fällen und für Dinge verwenden, die nicht mit einer einfachen bedingten Anweisung getestet werden können. Sie müssen auch umso seltener geworfen werden.

Dies ist eine zufällige Geschichte für Sie, aber ich denke, ich würde definitiv zweimal überlegen, bevor ich ab sofort Ausnahmen in meinem Code verwende!


Hallo, Entschuldigung für die späte Hinzufügung hier, aber wäre das nicht ein unfairer Test? Sie haben eine 'if'-Anweisung verwendet, um die Logik in Option 2 kurzzuschließen. Ein try catch-Block sollte if () null {try} else {try} sagen, richtig? Ich denke nicht, dass die Verwendung einer Ausnahme anstelle einer if-Anweisung dasselbe ist wie der Vergleich einer Ausnahme mit einem Rückkehrcode oder eine if-Prüfung, die einen Versuch auslöst.
Sean Brookins

@ SeanBrookins Sie wollen damit sagen, dass er "Ausnahmen fangen" und "überhaupt keine Ausnahmen" im Vergleich zu einem faireren Test testet, der "Ausnahmen fangen" und "Ausnahmen werfen / nicht fangen" wäre? Das ist fair, aber der Unterschied ist wahrscheinlich sehr gering.
Jspinella

Dies mag zutreffen, @jspinella, aber wenn Sie einen if-Block verwenden, der dann auch Ausnahmen verwendet (was meiner Meinung nach der beste Ansatz ist), werden Sie möglicherweise feststellen, dass Ausnahmen nicht sehr kostspielig sind. Die Verwendung von Ausnahmen anstelle von Logik verschlechterte die Leistung, aber Ausnahmen sollten für unerwartete Daten, nicht analysierbare Einträge usw. gelten und logische Prüfungen nicht ersetzen. Die Annahme, dass der Unterschied minimal ist, würde auch bedeuten, dass die anfängliche Beobachtung nicht hätte getestet werden sollen, ja?
Sean Brookins

1

Ich habe kürzlich C # -Ausnahmen (werfen und fangen) in einer Summationsschleife gemessen, die bei jeder Addition einen arithmetischen Überlauf auslöste. Der Wurf und Fang des arithmetischen Überlaufs betrug auf einem Quad-Core-Laptop etwa 8,5 Mikrosekunden = 117 KiloExceptions / Sekunde.


0

Ausnahmen sind teuer, aber es steckt noch mehr dahinter, wenn Sie zwischen Ausnahme- und Rückkehrcodes wählen möchten.

Historisch gesehen war das Argument, Ausnahme stellt sicher, dass Code gezwungen ist, mit der Situation umzugehen, während Rückkehrcodes ignoriert werden können. Ich habe diese Argumente nie favorisiert, da kein Programmierer ihre Codes absichtlich ignorieren und brechen möchte - insbesondere ein gutes Testteam / oder ein gutes Testteam Ein gut geschriebener Testfall wird die Rückkehrcodes definitiv nicht ignorieren.

Aus Sicht der modernen Programmierpraktiken muss die Verwaltung von Ausnahmen nicht nur auf ihre Kosten, sondern auch auf ihre Rentabilität hin überprüft werden.

1. Da die meisten Frontends von der API getrennt werden, wird eine Ausnahme ausgelöst. zB eine mobile App mit Rest-API. Dieselbe API kann auch für ein eckiges js-basiertes Web-Frontend verwendet werden.

In beiden Szenarien werden Rückkehrcodes anstelle von Ausnahmen bevorzugt.

2 .. Heute versuchen Hacker nach dem Zufallsprinzip, alle Webdienstprogramme zu beschädigen. Wenn sie in einem solchen Szenario ständig Ihre Anmelde-API für Apps angreifen und die App ständig Ausnahmen auslöst, werden Sie täglich mit Tausenden von Ausnahmen konfrontiert. Natürlich werden viele sagen, dass die Firewall sich um solche Angriffe kümmert. Allerdings geben nicht alle Geld für die Verwaltung einer dedizierten Firewall oder eines teuren Anti-Spam-Dienstes aus. Es ist besser, wenn Ihr Code auf diese Szenarien vorbereitet ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.