Просить разрешения или извиниться?
Я родом из фона python, где он часто говорил, что легче извиниться, чем запросить разрешение. В частности, с учетом двух фрагментов:
if type(A) == int:
do_something(A)
else:
do_something(int(A))
try:
do_something(A)
except TypeError:
do_something(int(A))
Тогда в большинстве сценариев использования второй будет быстрее, когда A обычно является целым числом (предполагая, что do_something нуждается в целых числах в качестве входных данных и будет быстро увеличивать его исключение), поскольку вы теряете логический тест из каждого цикла выполнения за счет более дорогостоящего исключения, но гораздо реже.
Что я хотел проверить, было ли это истинно в С#, или же логические тесты достаточно быстрые по сравнению с исключениями, чтобы сделать этот небольшой угловой случай?
О, и меня интересует только производительность релиза, а не отладка.
OK мой пример был слишком расплывчатым, попробуйте этот:
Наивное решение:
return float(A) % 20 # coerse A to a float so it'll only fail if we actually don't
# have anything that can be represented as a real number.
Логическое решение:
if isinstance(A, Number): # This is cheaper because we're not creating a new
return A % 20 # object unless we really have to.
else:
return float(A) %20
Решение, основанное на исключении:
try: # Now we're doing any logical tests in the 99% of cases where A is a number
return A % 20
except TypeError:
return float(A) % 20
Примеры использования FSO, подключений к базам данных или материала по сети лучше, но немного затянуты для вопроса.
Ответы
Ответ 1
Наверное, нет. Исключения .NET относительно дороги.
Некоторые функции .NET предлагают оба варианта по этой причине. (int.TryParse
, который возвращает код успеха, часто рекомендуется, потому что он быстрее, чем int.Parse
, который генерирует исключение при ошибке)
Но единственный ответ, который имеет значение, - это то, что вам сообщает ваше собственное профилирование.
Если вам нужна производительность, вам нужно измерить, измерить, измерить.
Поскольку то, что было самым быстрым на моем компьютере, с моим кодом, с моей версией .NET Framework, в настоящее время может быть не самым быстрым на вашем компьютере, с вашим кодом, с вашей версией .NET framework на время, когда вы его читаете.
Ответ 2
Исключения в .NET довольно тяжелы, поэтому философия на С# заключается в использовании исключений только для исключительных ситуаций, а не для потока программы.
Философия в С# также предназначена для проверки всех входных данных, полученных от внешнего кода, перед использованием. Пример:
public void Foo(int i)
{
if (i == 0) // validate input received from external code
{
throw new ArgumentOutOfRangeException("i");
}
DoSomething(i);
}
public void Foo()
{
DoSomething(1);
}
internal void DoSomething(int i)
{
Debug.Assert(i != 0); // validate that i is not zero in DEBUG build
// assume that i is not zero in RELEASE build
Console.WriteLine(42 / i);
}
Ответ 3
Как правило, я бы сказал, что исключения не должны использоваться для управления потоком. Используйте исключения для исключительных обстоятельств - поэтому, если вы ожидаете, что A будет int, тогда ваш первый подход разумный. Если это может быть int или строка, вторая более читаема.
По производительности - разница в выпуске - разумные логические тесты, конечно, достаточно быстры, поэтому лично я бы пошел на удобочитаемость.
Ответ 4
Исключения не должны использоваться в качестве "нормального" средства управления потоком выполнения, и да, они дороги.
В любом случае, я думаю, что ваш вопрос слегка ошибочен, исходя из python. С# является (или был?) Статически типизированным языком, что означает, что во время компиляции можно разрешить многие сценарии, похожие на то, что вы предлагаете.
Ответ 5
http://paltman.com/2008/01/18/try-except-performance-in-python-a-simple-test/ имеет аналогичный тест, за исключением просмотра has_key, который я ожидаю (немного) дороже, чем проверка типов.
В случае некоторого большого количества итераций, где ключ существует (поэтому исключение никогда не бросается), он примерно на 25% быстрее, но все еще довольно быстро. Где ключ никогда не существует, он примерно на 1000% медленнее.
Теперь, имея в виду, что проверка типов выполняется быстрее, чем поиск ключа, и что .Net-исключения, как уже упоминалось выше, имеют довольно тяжелый вес, вам нужно, чтобы A был целым числом в течение большей части времени, прежде чем он даже потенциально стоит.
Но, как упоминалось ранее. Попробуйте и посмотрите.