Я не хочу обсуждать, когда и не создавать исключения. Я хочу решить простой вопрос. В 99% случаев аргумент в пользу отказа от создания исключений вращается вокруг их медленности, в то время как другая сторона заявляет (с помощью эталонного теста), что проблема не в скорости. Я прочитал множество блогов, статей и сообщений, относящихся к той или иной стороне. Так что это?
К сожалению, в нескольких ответах, получивших большое количество голосов, упущен вопрос «Насколько медленны исключения?», И в частности, предлагается избегать темы о том, как часто их использовать. Один простой ответ на вопрос, который задается на самом деле: ... В Windows CLR исключения в 750 раз медленнее, чем возвращаемые значения.





В режиме выпуска накладные расходы минимальны.
Если вы не собираетесь использовать исключения для управления потоком (например, нелокальные выходы) рекурсивным образом, я сомневаюсь, что вы заметите разницу.
Я на стороне "не медленных" - или, точнее, "недостаточно медленных, чтобы их стоило избегать при нормальном использовании". Я написал об этом два короткаястатьи. Есть критика в отношении аспекта тестирования, которая в основном сводится к тому, что «в реальной жизни нужно было бы пройти больше стека, поэтому вы взорвали бы кеш и т. д.» - но использование кодов ошибок для продвижения вверх по стеку приведет к также взорвать кеш, так что я не считаю это особенно хорошим аргументом.
Просто чтобы прояснить - я не поддерживаю использование исключений там, где они не логичны. Например, int.TryParse полностью подходит для преобразования данных от пользователя. Это уместно при чтении сгенерированного машиной файла, где сбой означает: «Файл не в том формате, в котором он должен быть, я действительно не хочу пытаться справиться с этим, поскольку я не знаю, что еще может быть не так. "
При использовании исключений в «только разумных обстоятельствах» я никогда не встречал приложения, производительность которого существенно снижалась из-за исключений. По сути, исключения не должны происходить часто, если у вас нет серьезных проблем с корректностью, а если у вас есть серьезные проблемы с корректностью, производительность - не самая большая проблема, с которой вы сталкиваетесь.
к сожалению, людям говорят, что исключения бесплатны, используйте их для тривиальной «правильной» функциональности, их следует использовать, как вы говорите, когда что-то пошло не так - в «исключительных» обстоятельствах
Да, люди обязательно должны знать, что неправильное использование исключений связано с потерей производительности. Я просто думаю, что это не проблема, когда они являются используют должным образом :)
Следует отметить еще один момент: tryparse следует использовать, когда вы можете восстановиться после сбоя, иначе синтаксический анализ будет быстрее, чем "if (! Tryparse) throw"
На этот раз Джон Скит неправ. Я настроил множество приложений C#, и удаление исключений из логики счастливого пути - это невысокий плод. Одна только эта настройка удвоила время загрузки веб-сайта с очень высоким трафиком. Используйте Perfmon; если вы видите исключений в секунду в диапазоне 200+, вы получаете тривиальный прирост производительности
@PaulLockwood: Я бы сказал, что если у вас 200+ исключений на второй, вы злоупотребляете исключениями. Это явно не «исключительное» событие, если оно происходит 200 раз в секунду. Обратите внимание на последнее предложение ответа: «В принципе, исключения не должны происходить часто, если у вас нет серьезных проблем с корректностью, а если у вас серьезные проблемы с корректностью, производительность - не самая большая проблема, с которой вы сталкиваетесь».
200+ в секунду случаются гораздо чаще, чем можно было бы предположить. Я настроился на многие компании, практически на каждом сайте с высокой посещаемостью была такая проблема. Я однажды видел сайт с ~ 30 четырехъядерными серверами, у которых скорость выше 1000 / с! (только шесть в DMZ обрабатывают прямой веб-трафик, но все же ...) Из опыта Исключения медленные, но, как и в случае с отражением, если это происходит нечасто, то в этом нет ничего страшного.
@PaulLockwood: Я хочу сказать, что если у вас 200+ исключений в секунду, это, вероятно, указывает на то, что вы злоупотребляете исключениями. Меня не удивляет, что это часто случается, но это означает, что аспект производительности не будет моей первой проблемой - будет злоупотребление исключениями. После того, как я удалил все случаи использования исключений неприличный, я бы не ожидал, что они будут значительной частью производительности.
соглашаться. Разработчики могут злоупотреблять многими вещами и избегать наказания за это (благодаря современному оборудованию / компиляторам). Исключения, такие как Reflection, не нуждаются в злоупотреблении, прежде чем окажут значительное влияние
Страшно, что за этот ответ проголосовали так высоко. Исключения (по сравнению с возвращаемыми значениями) в .NET НЕВЕРОЯТНО медленны. Мой тест показывает, что они примерно в 1400 раз медленнее, чем возвращаемые значения. (см. ниже)
@DavidJeske: Вы упустили суть ответа. Очевидно, что создание исключения происходит намного медленнее, чем возврат нормального значения. Никто с этим не спорит. Вопрос в том, медленные ли они тоже. Если вы находитесь в ситуации подходящее для выброса исключения и, которое вызывает проблемы с производительностью, то у вас, вероятно, проблемы посерьезнее - потому что это предполагает, что в вашей системе огромное количество неправильный. Обычно проблема в том, что В самом деле вы используете исключения, когда они неуместны для начала.
Одно забавное неправильное использование исключений - это PowerShell, где break и continue реализованы таким образом и, следовательно, работают ужасно медленно. Конечно, таких затрат вы не ожидаете при написании цикла с использованием этих конструкций.
@Jon Skeet - и все же исходный вопрос заключается не в том, когда использовать исключения, а в их производительности. Исключения в Windows CLR очень медленные, нет вопросов. Использует ли кто-то их слишком много или нет - это отдельный вопрос. В некоторых средах выполнения и языках исключения являются приемлемым нелокальным программным элементом управления для различных обстоятельств. В CLR их нет. В частности, они слишком медленны, чтобы их можно было использовать в коде библиотеки, потому что вы никогда не знаете, как часто кому-то нужно вызывать вашу библиотеку.
@DavidJeske: Но их работа имеет значение только в контексте, ИМО. При правильном использовании они достаточно быстрые и не повлияют на производительность вашего приложения. При использовании в неправильном месте они медленные и полностью убьют его.
В Windows CLR исключения в 750 раз медленнее, чем возвращаемые значения (см. Мой ответ). Этот тест и вывод, что они «не медленные», неверны.
@DavidJeske - Это похоже на проблему контроля над оружием, которая широко распространена в США. Оружие безопасно при правильном использовании. Исключения быстро используются надлежащим образом. Может ли оружие быть опасным? да. Могут ли исключения быть медленными? да. Черт возьми, нам повезло, что нет поправки на право создавать исключения.
В моем тесте в режиме выпуска исключение .NET, выброшенное и пойманное одним и тем же методом, занимает около 15 микросекунд, или 0,000015 секунды.
@Enigmativity Нет, исключения CLR всегда выполняются медленно. Если их использовать экономно, такая медлительность может не быть проблемой. Управление этим может быть проблематичным, если оно выходит за рамки библиотеки. Например, не используйте индексаторы Dictionary и исключение KeyNotFound, когда ключи могут часто отсутствовать, потому что это будет мешать вашему приложению. Вместо этого используйте TryGetValue. Однако не все библиотеки будут предоставлять версии каждого API как с исключениями, так и без них. Это шизофренический подход к дизайну API, когда все нужно делать дважды.
@DavidJeske - Я хотел сказать, что если их использовать экономно, с ними все в порядке, но на самом деле большинство разработчиков ими злоупотребляют.
Аргумент, насколько я понимаю, не в том, что выбрасывать исключения - это плохо, они сами по себе медленные. Вместо этого речь идет об использовании конструкции throw / catch в качестве первоклассного способа управления нормальной логикой приложения вместо более традиционных условных конструкций.
Часто в нормальной логике приложения вы выполняете цикл, в котором одно и то же действие повторяется тысячи / миллионы раз. В этом случае с помощью очень простого профилирования (см. Класс Stopwatch) вы можете сами убедиться, что выброс исключения вместо простого оператора if может оказаться значительно медленнее.
Фактически я однажды прочитал, что команда .NET в Microsoft представила методы TryXXXXX в .NET 2.0 для многих базовых типов FCL, особенно потому, что клиенты жаловались на то, что их приложения работают так медленно.
Оказывается, во многих случаях это было потому, что клиенты пытались преобразовать типы значений в цикле, и каждая попытка терпела неудачу. Возникло исключение преобразования, которое затем было перехвачено обработчиком исключений, который затем проглотил исключение и продолжил цикл.
Теперь Microsoft рекомендует использовать методы TryXXX, особенно в этой ситуации, чтобы избежать таких возможных проблем с производительностью.
Я могу ошибаться, но похоже, что вы не уверены в достоверности «тестов», о которых читали. Простое решение: попробуйте сами.
Я думал, что эти «пробные» функции тоже используют исключения?
Эти функции «Попробовать» не создают внутренних исключений при неудачном анализе входного значения. Однако они по-прежнему генерируют исключения для других ошибочных ситуаций, таких как ArgumentException.
Я думаю, что этот ответ ближе к сути проблемы, чем любой другой. Сказание «использовать исключения только в разумных обстоятельствах» на самом деле не дает ответа на вопрос - настоящее понимание состоит в том, что использование исключений C# для потока управления происходит намного медленнее, чем обычные условные конструкции. Вы могли бы быть прощены за то, что думали иначе. В OCaml исключения - это более или менее GOTO и общепринятый способ реализации перерыв при использовании императивных функций. В моем конкретном случае замена в замкнутом цикле int.Parse () плюс попробуй поймать против int.TryParse () дала значительный прирост производительности.
У меня никогда не было проблем с производительностью с исключениями. Я часто использую исключения - я никогда не использую коды возврата, если могу. Это плохая практика и, на мой взгляд, пахнет спагетти-кодом.
Я думаю, все сводится к тому, как вы используете исключения: если вы используете их как коды возврата (каждый вызов метода в стеке улавливает и перебрасывает), то да, они будут медленными, потому что у вас есть накладные расходы на каждый отдельный улов / бросок.
Но если вы бросаете в нижнюю часть стека и ловите наверху (вы заменяете целую цепочку кодов возврата на один бросок / улов), все дорогостоящие операции выполняются один раз.
В конце концов, это допустимая языковая функция.
Просто чтобы доказать свою точку зрения
Пожалуйста, запустите код по этой ссылке (слишком большой для ответа).
Результаты на моем компьютере:
marco@sklivvz:~/develop/test$ mono Exceptions.exe | grep PM
10/2/2008 2:53:32 PM
10/2/2008 2:53:42 PM
10/2/2008 2:53:52 PM
Отметки времени выводятся в начале, между кодами возврата и исключениями, в конце. В обоих случаях требуется одинаковое время. Обратите внимание, что вы должны компилировать с оптимизацией.
Если вы сравните их с кодами возврата, они будут чертовски медленными. Однако, как указывалось в предыдущих плакатах, вы не хотите запускать нормальную работу программы, поэтому вы получаете результат только при возникновении проблемы, и в подавляющем большинстве случаев производительность больше не имеет значения (поскольку исключение в любом случае подразумевает преграду).
Их определенно стоит использовать вместо кодов ошибок, преимущества огромны, ИМО.
На это есть окончательный ответ от парня, который их реализовал - Криса Брамме. Он написал отличная статья в блоге о предмете (предупреждение - оно очень длинное) (предупреждение 2 - оно очень хорошо написано, если вы технарь, вы прочитаете его до конца, а затем придется наверстывать свои часы после работы :))
Резюме: они медленные. Они реализованы как исключения Win32 SEH, поэтому некоторые из них даже преодолевают границу ЦП 0 кольца! Очевидно, что в реальном мире вы будете выполнять много другой работы, поэтому странные исключения вообще не будут замечены, но если вы используете их для выполнения программы, ожидайте, что ваше приложение будет повреждено. Это еще один пример того, как маркетинговая машина MS оказывает нам медвежью услугу. Я вспоминаю, как один микрософт рассказывал нам, как они не несли абсолютно нулевые накладные расходы, а это полная чушь.
Крис приводит уместную цитату:
In fact, the CLR internally uses exceptions even in the unmanaged portions of the engine. However, there is a serious long term performance problem with exceptions and this must be factored into your decision.
Я могу упомянуть об этом в реальных тестах, где тип, допускающий значение NULL, вызывает исключение, которое возникает много раз в «это нормальный поток программы», что приводит к значительным проблемам с производительностью. Всегда помните, исключения - для исключительных случаев, не верьте никому, кто говорит иначе, иначе у вас получится такая ветка на github!
Я понятия не имею, о чем говорят люди, когда говорят, что они медленные, только если их бросают.
Обновлено: если исключения не генерируются, это означает, что вы выполняете new Exception () или что-то в этом роде. В противном случае исключение приведет к приостановке потока и обходу стека. Это может быть нормально в небольших ситуациях, но на веб-сайтах с высоким трафиком использование исключений в качестве рабочего процесса или механизма пути выполнения, безусловно, вызовет проблемы с производительностью. Исключения сами по себе неплохи и полезны для выражения исключительных условий.
Рабочий процесс исключений в приложении .NET использует исключения первого и второго шансов. Для всех исключений, даже если вы их перехватываете и обрабатываете, объект исключения все равно создается, и фреймворк по-прежнему должен пройти по стеку в поисках обработчика. Если вы поймаете и повторно выбросите, конечно, это займет больше времени - вы получите исключение первого шанса, поймаете его, повторно выбросите, что вызовет другое исключение первого шанса, которое затем не найдет обработчик, что затем вызовет исключение второго шанса.
Исключения также являются объектами в куче, поэтому, если вы выбрасываете тонны исключений, вы вызываете проблемы как с производительностью, так и с памятью.
Кроме того, согласно моей копии «Тестирования производительности веб-приложений Microsoft .NET», написанной командой ACE:
"Обработка исключений обходится дорого. Выполнение задействованного потока приостанавливается, пока CLR рекурсивно проходит через стек вызовов в поисках правильного обработчика исключения, и когда он будет найден, обработчик исключения и некоторое количество блоков finally должны иметь шанс на выполнение. прежде, чем можно будет проводить регулярную обработку ".
Мой собственный опыт работы в этой области показал, что уменьшение количества исключений значительно повысило производительность. Конечно, есть и другие вещи, которые вы принимаете во внимание при тестировании производительности - например, если ваш дисковый ввод-вывод снят или ваши запросы выполняются в секундах, тогда это должно быть вашим фокусом. Но поиск и удаление исключений должны быть жизненно важной частью этой стратегии.
Ничто из того, что вы написали, не противоречит утверждению, что исключения работают медленно, только если они генерируются. Вы говорили только о ситуациях, когда они бросают являются. Когда вы «значительно повысили производительность», удалив исключения: 1) Были ли они истинными ошибочными состояниями или просто ошибкой Пользователь?
2) Вы работали под отладчиком или нет?
Единственное, что вы можете сделать с исключением, если не выбросить его, - это создать его как объект, что бессмысленно. Находиться в отладчике или нет, не имеет значения - он все равно будет медленнее. Да, есть ловушки, которые могут произойти с подключенным отладчиком, но это все равно медленно.
Итак, Джон - я думаю, вы говорите, что случайные исключения не имеют большого значения. Я с тобой согласен. Но в вызовах perf, которые я делал с крупными клиентами, мы сначала проверяли, включена ли «отладка» в их веб-приложениях, а затем сколько исключений они генерировали. Это имеет значение.
Это, безусловно, медленнее, чем использование кода возврата, но насколько медленнее, имеет большое значение. Если генерация исключения занимает миллисекунду, то это не имеет значения, возникающее несколько тысяч раз в час. Если это займет секунду, это очень важно!
Сколько исключений мы выкидывают ваши клиенты, кстати? Не забывайте, что по умолчанию Response.Redirect выдает исключение ...
Я знаю - я был частью премьер-команды MSFT. :) Скажем так, много - тысячи в секунду в некоторых крайних случаях мы видели. Нет ничего лучше, чем подключиться к живому отладчику и просто увидеть исключения так быстро, как вы могли бы читать. Ex медленные - как и подключение к БД, поэтому вы делаете это, когда это имеет смысл.
Кори, я думаю, что смысл выражения «только медленные, когда их бросают» заключается в том, что вам не нужно беспокоиться о производительности из-за простого наличия блоков catch / finally. Т.е. сами по себе они не вызывают снижения производительности, а только появление фактического экземпляра исключения.
Мой сервер XMPP значительно увеличил скорость (извините, фактических цифр нет, чисто наблюдательный) после того, как я постоянно пытался предотвратить их появление (например, проверять, подключен ли сокет, прежде чем пытаться прочитать больше данных) и давая себе способы избежать их (упомянутые методы TryX). Это было всего с 50 активными (болтающими) виртуальными пользователями.
К сожалению, числа были бы полезны :( Такие вещи, как операции с сокетами, должны значительно перевешивать затраты на исключение, особенно если вы не отлаживаете. Если вы когда-нибудь проведете его полное тестирование, мне было бы очень интересно увидеть результаты.
Одно небольшое замечание о производительности, связанной с перехватом исключений.
Когда путь выполнения входит в блок «попытка», ничего волшебного не происходит. Здесь нет инструкции «попытаться» и нет затрат, связанных с входом в блок попытки или выходом из него. Информация о блоке try хранится в метаданных метода, и эти метаданные используются во время выполнения всякий раз, когда возникает исключение. Механизм выполнения спускается по стеку в поисках первого вызова, который содержался в блоке try. Любые накладные расходы, связанные с обработкой исключений, возникают только при возникновении исключения.
Однако наличие исключений может влияет на оптимизацию - методы с явными обработчиками исключений сложнее встроить, и переупорядочение инструкций ограничено ими.
Просто чтобы добавить к этому обсуждению свой недавний опыт: в соответствии с большей частью того, что написано выше, я обнаружил, что генерирование исключений происходит очень медленно, когда выполняется на постоянной основе, даже без запущенного отладчика. Я просто увеличил производительность большой программы, которую пишу, на 60%, изменив примерно пять строк кода: переключившись на модель кода возврата вместо выдачи исключений. Конечно, рассматриваемый код запускался тысячи раз и потенциально генерировал тысячи исключений, прежде чем я его изменил. Итак, я согласен с утверждением выше: генерировать исключения, когда что-то важное действительно идет не так, а не как способ управления потоком приложений в любых «ожидаемых» ситуациях.
Но моно генерирует исключение в 10 раз быстрее, чем автономный режим .net, и автономный режим .net генерирует исключение в 60 раз быстрее, чем режим отладчика .net. (Испытательные машины имеют одинаковую модель процессора)
int c = 1000000;
int s = Environment.TickCount;
for (int i = 0; i < c; i++)
{
try { throw new Exception(); }
catch { }
}
int d = Environment.TickCount - s;
Console.WriteLine(d + "ms / " + c + " exceptions");
В Windows CLR для цепочки вызовов глубины 8 генерирование исключения в 750 раз медленнее, чем проверка и распространение возвращаемого значения. (см. тесты ниже)
Такая высокая стоимость исключений объясняется тем, что среда CLR Windows интегрируется с чем-то, называемым Структурированная обработка исключений Windows. Это позволяет правильно перехватывать исключения и передавать их в разные среды выполнения и языки. Однако это очень-очень медленно.
Исключения в среде выполнения Mono (на любой платформе) намного быстрее, потому что она не интегрируется с SEH. Однако при передаче исключений в несколько сред выполнения происходит потеря функциональности, поскольку он не использует ничего подобного SEH.
Вот сокращенные результаты моего теста исключений и возвращаемых значений для Windows CLR.
baseline: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.25 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.5 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 0.75 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 1 (0), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0 (0), time elapsed 13.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.25 (249999), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.5 (499999), time elapsed 16.0009 ms
retval_error: recurse_depth 5, error_freqeuncy 0.75 (999999), time elapsed 16.001 ms
retval_error: recurse_depth 5, error_freqeuncy 1 (999999), time elapsed 16.0009 ms
retval_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 20.0011 ms
retval_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 21.0012 ms
retval_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 24.0013 ms
exception_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 31.0017 ms
exception_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 5607.3208 ms
exception_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 11172.639 ms
exception_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 22297.2753 ms
exception_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 22102.2641 ms
А вот и код ..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1 {
public class TestIt {
int value;
public class TestException : Exception { }
public int getValue() {
return value;
}
public void reset() {
value = 0;
}
public bool baseline_null(bool shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
return shouldfail;
} else {
return baseline_null(shouldfail,recurse_depth-1);
}
}
public bool retval_error(bool shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
if (shouldfail) {
return false;
} else {
return true;
}
} else {
bool nested_error = retval_error(shouldfail,recurse_depth-1);
if (nested_error) {
return true;
} else {
return false;
}
}
}
public void exception_error(bool shouldfail, int recurse_depth) {
if (recurse_depth <= 0) {
if (shouldfail) {
throw new TestException();
}
} else {
exception_error(shouldfail,recurse_depth-1);
}
}
public static void Main(String[] args) {
int i;
long l;
TestIt t = new TestIt();
int failures;
int ITERATION_COUNT = 1000000;
// (0) baseline null workload
for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {
int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);
failures = 0;
DateTime start_time = DateTime.Now;
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
bool shoulderror = (i % EXCEPTION_MOD) == 0;
t.baseline_null(shoulderror,recurse_depth);
}
double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
Console.WriteLine(
String.Format(
"baseline: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
recurse_depth, exception_freq, failures,elapsed_time));
}
}
// (1) retval_error
for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {
int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);
failures = 0;
DateTime start_time = DateTime.Now;
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
bool shoulderror = (i % EXCEPTION_MOD) == 0;
if (!t.retval_error(shoulderror,recurse_depth)) {
failures++;
}
}
double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
Console.WriteLine(
String.Format(
"retval_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
recurse_depth, exception_freq, failures,elapsed_time));
}
}
// (2) exception_error
for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {
int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);
failures = 0;
DateTime start_time = DateTime.Now;
t.reset();
for (i = 1; i < ITERATION_COUNT; i++) {
bool shoulderror = (i % EXCEPTION_MOD) == 0;
try {
t.exception_error(shoulderror,recurse_depth);
} catch (TestException e) {
failures++;
}
}
double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
Console.WriteLine(
String.Format(
"exception_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
recurse_depth, exception_freq, failures,elapsed_time)); }
}
}
}
}
Помимо упущения сути вопроса, пожалуйста, не используйте DateTime.Now для тестов - используйте секундомер, который предназначен для измерения прошедшего времени. Это не должно быть проблемой, поскольку вы измеряете достаточно длительные периоды времени, но это стоит привыкнуть.
Напротив, вопрос в том, "являются ли исключения медленными", точка. Он специально просил избегать темы, когда создавать исключения, потому что эта тема скрывает факты. Какова производительность исключений?
При написании классов / функций для использования другими, кажется, трудно сказать, когда уместны исключения. Есть некоторые полезные части BCL, от которых мне пришлось отказаться и перейти на pinvoke, потому что они генерируют исключения вместо того, чтобы возвращать ошибки. В некоторых случаях вы можете обойти это, но для других, таких как System.Management и Performance Counters, есть случаи, когда вам нужно выполнять циклы, в которых BCL часто генерирует исключения.
Если вы пишете библиотеку и существует отдаленная вероятность того, что ваша функция может быть использована в цикле и существует вероятность большого количества итераций, используйте шаблон Try .. или какой-либо другой способ выявить ошибки помимо исключений. И даже тогда трудно сказать, сколько будет вызываться ваша функция, если она будет использоваться многими процессами в общей среде.
В моем собственном коде исключения генерируются только тогда, когда что-то настолько исключительное, что необходимо посмотреть трассировку стека и посмотреть, что пошло не так, а затем исправить это. Поэтому я в значительной степени переписал части BCL, чтобы использовать обработку ошибок на основе шаблона Try .. вместо исключений.
Похоже, это не соответствует заявлению плаката "Я не хочу обсуждать, когда и не создавать исключения".
Думаю, вы в значительной степени ответили на свой вопрос. Вы и почти все, кто их понимает, знаете, что они медленные. Это стопроцентный факт, но, как отмечали многие другие, контекст - это то, что на 100% имеет значение, когда их использовать. Пишете не серверное приложение? вы никогда не заметите разницы. Написание общедоступного API веб-сайта, в котором неверно сформированный клиентский запрос может вызвать исключение на сервере? Это рецепт катастрофы, умноженный на количество запросов в секунду. Backends привязаны больше раз, чем копейка пони в продуктовом магазине. Однако проблема заключается в том, что BCL / другие библиотеки будут генерировать исключения, которые вы не можете контролировать, поэтому вам нужно установить промежуточные элементы, которые будут запускать эти исключения до того, как они попадут в BCL. Бывают случаи, когда у вас вообще нет защиты. Например, обращение к базе данных MongoDB с помощью MongoClient. Все функции MongoCollection. * Async будут генерировать исключения, если они не преуспеют в определенных сценариях, но они вообще не вызывают многих, и я почти уверен, что эти сценарии находятся на редком конце спектра (что смещает это в сторону контекста часть ситуации). Хотя я тоже мог ошибаться. Я просто предполагаю, что они бросали только в редких случаях. Как вы отметили, вы знаете, что они медленные, поэтому здравый смысл подсказывает, что вы используете их в контекстах, требующих, чтобы работа не замедлялась. Легко и просто.
есть ложь, проклятая ложь и ориентиры. :)