Насколько дороги исключения в C #? - PullRequest
66 голосов
/ 21 мая 2009

Насколько дороги исключения в C #? Кажется, что они не невероятно дороги, пока стек не глубокий; однако я прочитал противоречивые сообщения.

Есть ли окончательный отчет, который не был опровергнут?

Ответы [ 7 ]

64 голосов
/ 21 мая 2009

Джон Скит написал Исключения и производительность в .NET в январе 2006

Что было обновлено Исключения и производительность Redux (спасибо @Gulzar)

На что Рико Мариани присоединился Истинная цена исключений .NET - решение


Также ссылка: Кшиштоф Квалина - Обновление рекомендаций по проектированию: исключение

15 голосов
/ 10 января 2011

Прочитав, что исключения являются дорогостоящими с точки зрения производительности, я составил простую программу измерений, очень похожую на ту, которую Джон Скит опубликовал несколько лет назад . Я упоминаю это здесь в основном, чтобы предоставить обновленные номера.

Программа обработала менее 29914 миллисекунд, чтобы обработать миллион исключений, что составляет 33 исключений в миллисекунду . Это достаточно быстро, чтобы сделать исключения жизнеспособной альтернативой кодам возврата для большинства ситуаций.

Обратите внимание, однако, что с кодами возврата вместо исключений одна и та же программа выполняется менее одной миллисекунды, что означает, что исключения как минимум в 30000 раз медленнее, чем коды возврата . Как подчеркнул Рико Мариани , эти числа также являются минимальными числами. На практике создание и отлов исключений займет больше времени.

Измерено на ноутбуке с Intel Core2 Duo T8100 @ 2,1 ГГц с версией .NET 4.0 в сборке выпуска не работает под отладчиком (что может замедлить работу).

Это мой тестовый код:

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;
}
14 голосов
/ 21 мая 2009

Полагаю, я в лагере, и если производительность исключений влияет на ваше приложение, вы выбрасываете WAY их слишком много. Исключения должны быть для исключительных условий, а не для обычной обработки ошибок.

Тем не менее, мое воспоминание о том, как обрабатываются исключения, по сути идет вверх по стеку, находя оператор catch, соответствующий типу создаваемого исключения. Таким образом, на производительность больше всего повлияет то, насколько глубоко вы находитесь в улове и сколько у вас заявлений о вылове.

4 голосов
/ 21 февраля 2012

В моем случае исключения были очень дорогими. Я переписал это:

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

В это:

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

И заметил хорошее увеличение скорости примерно на 30 секунд. Эта функция вызывается как минимум 32K раз при запуске. Код не настолько ясен, как задумано, но экономия была огромной.

3 голосов
/ 16 мая 2016

Я провел свои собственные измерения, чтобы выяснить, насколько серьезны последствия исключений. Я не пытался измерить абсолютное время для исключения / броска. Больше всего меня интересовало, насколько медленнее будет цикл, если в каждом проходе будет создаваться исключение. Измерительный код выглядит следующим образом

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

против

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

Разница в 20 раз. Второй фрагмент медленнее в 20 раз.

3 голосов
/ 21 мая 2009

Объекты исключений Barebones в C # довольно легкие; обычно способность инкапсулировать InnerException делает его тяжелым, когда дерево объектов становится слишком глубоким.

Что касается окончательного отчета, я не знаю ни одного, хотя краткий профиль dotTrace (или любой другой профилировщик) для потребления памяти и скорости будет довольно легко сделать.

2 голосов
/ 21 мая 2009

Кажется, что производительность падает с исключениями в момент создания объекта исключения (хотя он слишком мал, чтобы вызывать какие-либо проблемы в 90% случаев). Поэтому рекомендуется профилировать ваш код - если исключения равны , вызывающие снижение производительности, вы пишете новый метод с высоким быстродействием, который не использует исключения. (Пример, который приходит на ум, будет (TryParse введен, чтобы преодолеть проблемы перфорирования с Parse, который использует исключения)

При этом исключения в большинстве случаев не приводят к значительному снижению производительности в большинстве ситуаций - поэтому Руководство по проектированию MS предназначено для сообщения об ошибках путем создания исключений

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...