Чтобы спросить разрешение или извиниться?
Я родом из питона, где часто говорят, что легче извиниться, чем спрашивать разрешения. Специально дано два фрагмента:
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 требует целое число в качестве входных данных и вызовет его исключение довольно быстро), так как вы теряете логический тест из каждого цикла выполнения за счет более дорогостоящее исключение, но гораздо реже.
Я хотел проверить, так ли это в C#, или же логические тесты достаточно быстры по сравнению с исключениями, чтобы сделать это маленьким угловым случаем?
Ох, и меня интересует только выпуск релиза, а не отладка.
ОК, мой пример был слишком расплывчатым, попробуйте этот:
Наивное решение:
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, соединений с базами данных или чего-то другого по сети лучше, но немного скучны для вопроса.
5 ответов
Возможно нет. Исключения.NET относительно дороги.
По этой причине несколько функций.NET предлагают оба варианта. (int.TryParse
, который возвращает код успеха, часто рекомендуется, потому что он быстрее, чем int.Parse
который выдает исключение при неудаче)
Но единственный ответ, который имеет значение, - это то, что говорят ваши собственные данные профилирования. Если вам нужна производительность, то вам нужно измерить, измерить, измерить.
Потому что то, что было самым быстрым на моем компьютере, с моим кодом, с моей версией.NET Framework, в настоящее время может быть не самым быстрым на вашем компьютере, с вашим кодом, с вашей версией.NET Framework в то время, когда вы прочитай это.
Исключения в.NET довольно тяжелые, поэтому философия в C# - использовать исключения только для исключительных ситуаций, а не для выполнения программы.
Философия C# также направлена на проверку всего ввода, полученного из внешнего кода, перед его использованием. Пример:
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);
}
Как правило, я бы сказал, что исключения не должны использоваться для управления потоком. Используйте исключения для исключительных обстоятельств - поэтому, если вы ожидаете, что A будет int, тогда ваш первый подход будет разумным. Если это может быть int или строка, вторая будет более читаемой.
С точки зрения производительности есть разница в сборке релиза - разумные логические тесты, безусловно, достаточно быстрые - так что лично я бы пошел на удобочитаемость.
Исключения не должны использоваться в качестве "нормального" инструмента управления потоком выполнения, и да, они дороги.
Во всяком случае, я думаю, что ваш вопрос слегка ошибочный, пришедший из python. C# является (или был?) Языком со статической типизацией, что означает, что многие сценарии, аналогичные тем, которые вы предлагаете, могут быть разрешены во время компиляции.
http://paltman.com/2008/01/18/try-except-performance-in-python-a-simple-test/ имеет аналогичный тест, за исключением того, что смотрит на has_key, который я бы ожидал (слегка) дороже, чем проверка типов.
В случае большого количества итераций, когда ключ существует (поэтому исключение не выдается), он примерно на 25% быстрее, но все еще довольно быстр. Там, где ключ никогда не существует, он примерно на 1000% медленнее.
Теперь, имея в виду, что проверка типов выполняется быстрее, чем поиск ключа, и что исключения.Net, как уже упоминалось выше, являются достаточно тяжелыми, вам понадобится A, чтобы быть целым числом в подавляющем большинстве случаев, прежде чем оно даже станет потенциально полезным.
Но, как упоминал ранее Джалф. Попробуйте и посмотрите.