93 votes

Combien coûtent les exceptions en C #?

Combien coûtent les exceptions en C #? Il semble qu’ils ne soient pas incroyablement coûteux tant que la pile n’est pas profonde; Cependant, j'ai lu des rapports contradictoires.

Y a-t-il un rapport définitif qui n'a pas été réfuté?

74voto

Robert Paulson Points 10792

Jon Skeet a écrit des Exceptions et de la Performance dans .NET en janvier 2006

Qui a été mis à jour Exceptions et les Performances Redux (merci @Gulzar)

Pour ce qui Rico Mariani de renchérir le Coût réel de La .NET Exceptions -- Solution


Également de référence: Krzysztof Cwalina - lignes Directrices de Conception de mise à Jour: Exception Jeter

37voto

Helge Klein Points 3939

Ayant lu que les exceptions sont coûteuses en termes de performance, j'ai jeté un simple programme de mesure, très semblable à celui de Jon Skeet publiée il y a des années. J'en parle ici principalement à fournir des chiffres mis à jour.

Il a fallu le programme ci-dessous 29914 millisecondes pour traiter un million d'exceptions, qui s'élève à 33 exceptions par milliseconde. C'est assez rapide à faire des exceptions une alternative viable aux codes de retour pour la plupart des situations.

Veuillez noter, cependant, que avec les codes de retour au lieu d'exceptions près le même programme s'exécute en moins d'une milliseconde, ce qui signifie que les exceptions sont à moins de 30 000 fois plus lent que les codes de retour. Comme l'a souligné Rico Mariani ces numéros sont également le nombre minimum de participants. Dans la pratique, lancer et attraper une exception prendra plus de temps.

Mesurée sur un ordinateur portable avec processeur Intel Core 2 Duo T8100 @ 2,1 GHz avec .NET 4.0 en version release pas s'exécuter sous le débogueur (ce qui serait beaucoup plus lent).

C'est mon code de test:

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;
}

30voto

Colin Burnett Points 4572

Je suppose que je suis dans le camp que si les performances des exceptions ont une incidence sur votre demande puis vous lancez FAÇON beaucoup trop. Les Exceptions doivent être pour des conditions exceptionnelles, pas de routine de gestion d'erreur.

Cela dit, mon souvenir de la façon dont les exceptions sont gérées essentiellement à pied jusqu'à la pile de trouver une instruction catch qui correspond au type de l'exception levée. De sorte que les performances seront les plus touchées par la profondeur à laquelle vous êtes à partir de la capture, et combien d'attraper les déclarations que vous avez.

6voto

Mark Points 49079

Dans mon cas, les exceptions étaient très chères. J'ai réécrit ceci:

 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];
        }
    }
}
 

Dans ceci:

 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]];
    }
}
 

Et remarqué une bonne augmentation de vitesse d'environ 30 secondes. Cette fonction est appelée au moins 32 000 fois au démarrage. Le code n’est pas aussi clair quant à l’intention, mais les économies réalisées sont énormes.

4voto

Jon Limjap Points 46429

Les objets d'exception Barebones en C # sont assez légers; c'est généralement la possibilité d'encapsuler un InnerException qui le rend lourd lorsque l'arborescence d'objets devient trop profonde.

En ce qui concerne un rapport définitif, je n'en connais aucun, même si un profil dotTrace sommaire (ou tout autre profileur) pour la consommation de mémoire et la vitesse sera assez facile à réaliser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X