Подтвердить что ты не робот

Просить разрешения или извиниться?

Я родом из фона 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, подключений к базам данных или материала по сети лучше, но немного затянуты для вопроса.

4b9b3361

Ответ 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 был целым числом в течение большей части времени, прежде чем он даже потенциально стоит.

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