Насколько дороги исключения в C#?
насколько дороги исключения в C#? Похоже, что они не невероятно дороги, пока стек не глубок; однако я читал противоречивые отчеты.
есть ли окончательный отчет, который не был опровергнут?
7 ответов:
Джон Скит написал исключения и производительность в .NET в январе 2006
, который был обновлен исключения и снижение производительности (спасибо @Gulzar)
к которому присоединился Рико Мариани истинная стоимость исключений .NET -- Solution
также ссылка: Кшиштоф Cwalina -Обновление Руководящих Принципов Проектирования: Исключение Бросая
Я думаю, что я в лагере, что если производительность исключений влияет на ваше приложение, то вы бросаете путь их слишком много. Исключения должны быть для исключительных условий, а не как обычная обработка ошибок.
тем не менее, мое воспоминание о том, как обрабатываются исключения, по существу идет вверх по стеку, находя оператор catch, который соответствует типу вызванного исключения. Таким образом, производительность будет зависеть от того, насколько глубоко вы находитесь от поймайте и сколько у вас есть утверждений catch.
прочитав, что исключения являются дорогостоящими с точки зрения производительности, я собрал простую программу измерения, очень похожую на ту Джон Скит опубликован много лет назад. Я упоминаю об этом здесь в основном для предоставления обновленных номеров.
программе потребовалось менее 29914 миллисекунд, чтобы обработать миллион исключений, что составляет 33 исключения в миллисекунду. Это достаточно быстро, чтобы сделать исключения жизнеспособной альтернативой кодам возврата для большинства положения.
исключения по крайней мере в 30 000 раз медленнее, чем коды возврата. Как подчеркнул Рико Мариани эти числа также являются минимальными числами. На практике выбрасывание и отлов исключения займет больше времени.измеряется на ноутбуке с 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; }
объекты исключения Barebones в C# довольно легкие; обычно это возможность инкапсулировать
InnerException
Это делает его тяжелым, когда дерево объектов становится слишком глубоким.что касается окончательного отчета, я не знаю ни одного, хотя беглый профиль dotTrace (или любой другой профилировщик) для потребления памяти и скорости будет довольно легко сделать.
в моем случае, исключение составили очень дорого. Я переписал это:
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 раз при запуске. Код не так ясно, что такое намерение, но экономия средств была огромной.
хит производительности с исключениями, кажется, находится в точке генерации объекта исключения (хотя и слишком мал, чтобы вызвать какие-либо проблемы 90% времени). Поэтому рекомендуется профилировать ваш код-если исключения are вызывая снижение производительности, вы пишете новый метод высокой производительности, который не использует исключения. (Пример, который приходит на ум, был бы (TryParse введен для преодоления проблем perf с синтаксическим анализом, который использует исключения)
Что сказал, исключения в большинстве случаев не вызывают значительных хитов производительности в большинстве случаев - так MS Design Guideline должен сообщать о сбоях, бросая исключения
Я сделал свои собственные измерения, чтобы выяснить, насколько серьезны последствия исключений. Я не пытался измерить абсолютное время для исключения броска/ловли. Меня больше всего интересовало, насколько медленнее цикл станет, если исключение будет выдаваться на каждом проходе. Измерительный код выглядит так
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; }
разница составляет 20 раз. Второй фрагмент в 20 раз медленнее.