Чтобы спросить разрешение или извиниться? - PullRequest
12 голосов
/ 10 июня 2011

Я родом из питона, где часто говорят, что легче извиниться, чем спрашивать разрешения. Специально дано два фрагмента:

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 ]

15 голосов
/ 10 июня 2011

Наверное, нет.Исключения .NET относительно дороги.

По этой причине некоторые функции .NET предлагают оба варианта.(int.TryParse, который возвращает код успеха, часто рекомендуется, потому что он быстрее, чем int.Parse, который выдает исключение при сбое)

Но единственный ответ, который имеет значение, - это то, что говорят ваши собственные данные профилирования.Если вам нужна производительность, то вам нужно измерить, измерить, измерить.

Потому что то, что было быстрее всего на моем компьютере, с моим кодом, с моим версия .NET Framework, в это время может быть не самым быстрым на вашем компьютере, с вашим кодом, с вашей версией .NET Framework в то время, когдаВы читаете это.

7 голосов
/ 10 июня 2011

Исключения в .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);
}
6 голосов
/ 10 июня 2011

Как правило, я бы сказал, что исключения не должны использоваться для управления потоком. Используйте исключения для исключительных обстоятельств - поэтому, если вы ожидаете, что A будет int, тогда ваш первый подход будет разумным. Если это может быть int или строка, вторая будет более читабельной.

С точки зрения производительности, есть разница в сборке релиза - разумные логические тесты, конечно, достаточно быстрые - так что лично я бы пошел на читабельность.

3 голосов
/ 10 июня 2011

Исключения не должны использоваться в качестве "нормального" инструмента управления потоком выполнения, и да, они дороги.

Во всяком случае, я думаю, что ваш вопрос слегка ошибочен из-за питона. C # является (или был?) Статически типизированным языком, что означает, что многие сценарии, аналогичные тем, которые вы предлагаете, могут быть разрешены во время компиляции.

0 голосов
/ 10 июня 2011

http://paltman.com/2008/01/18/try-except-performance-in-python-a-simple-test/ имеет аналогичный тест, за исключением просмотра has_key, который, как я ожидаю, будет (немного) дороже, чем проверка типов.

Для случая большого количества итерацийтам, где ключ существует (таким образом, исключение никогда не выдается), он примерно на 25% быстрее, но все еще довольно быстр.Там, где ключ никогда не существует, он примерно на 1000% медленнее.

Теперь, имея в виду, что проверка типов выполняется быстрее, чем поиск ключа, и что исключения .Net, как упоминалось выше, довольно тяжелые, вам понадобитсяА быть целым числом в подавляющем большинстве случаев, прежде чем оно даже станет потенциально полезным.

Но, как упоминал ранее Джалф.Попробуйте и посмотрите.

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