Тест производительности нулевого указателя

Какова производительность проверки того, является ли переменная ссылочного типа в C# нулевым указателем (например, if (x == null) ...), по сравнению с проверкой целочисленного значения меньше нуля или даже логического значения false?

Известны ли другие проблемы, связанные с такими тестами нулевого указателя, например. производится ли мусор?

Я провожу сотни таких тестов для каждого кадра игры, и мне было интересно, могут ли они вызвать проблемы или их можно реализовать более эффективно?


person ares_games    schedule 11.01.2013    source источник
comment
Почему есть тег xna?   -  person Soner Gönül    schedule 11.01.2013
comment
Вы должны попробовать это, просто напишите несколько тестов производительности   -  person ken2k    schedule 11.01.2013
comment
Я не ожидаю большой разницы, я предполагаю, что вы оптимизируете больше / лучше, не повторяя один и тот же тест избыточно, чем заменяя ссылку проверками int.   -  person Emond Erno    schedule 11.01.2013
comment
Преждевременная оптимизация — корень всех зол..... Если я еще раз услышу эту цитату....   -  person Inisheer    schedule 11.01.2013
comment
@venneto ОП заявил, что делает игру на C #. Поэтому КРИТИЧЕСКИ ВАЖНО, чтобы вы не создавали мусор в каждом кадре, так как это приводит к запуску сборщика мусора. Следовательно, вы можете считать это НЕ преждевременной оптимизацией, поскольку это может напрямую изменить проектное решение.   -  person Inisheer    schedule 11.01.2013
comment
Почему вы вообще спрашиваете нас?   -  person SWeko    schedule 11.01.2013
comment
@Inisheer, но до того, как анализ n покажет, что это узкое место, оптимизировать его преждевременно. Эрик Липперт, знающий компилятор наизнанку, утверждает, что безнадежно ошибается в 1/3 случаев, когда пытается угадать проблемы с производительностью.   -  person Rune FS    schedule 11.01.2013
comment
@Inisheer: Да, именно! Возможные проблемы с производительностью второстепенны. Часть моего вопроса о производстве мусора также оправдывает теги XNA ;-) В настоящее время я отслеживаю последние байты памяти, которые выделяются во время игры...   -  person ares_games    schedule 11.01.2013
comment
@SWeko: Иногда между способами реализации вещей существуют неотъемлемые и очевидные различия в производительности. Я не совсем понимаю, как выполняется внутренний тест нулевого указателя, поэтому я не был в этом уверен, поэтому и спросил. Конечно, я мог бы заменить все тесты в своем исходном коде и измерить разницу самостоятельно, но это заняло бы у меня несколько дней.   -  person ares_games    schedule 11.01.2013
comment
@pad_ares: 1. Сделай это. 2. Запустите его. 3. Заставьте его работать быстро. В этой последовательности :)   -  person SWeko    schedule 11.01.2013
comment
Я думаю, что многие из тех, кто говорит оптимизировать позже, никогда не разрабатывали игру на управляемом языке.   -  person Inisheer    schedule 11.01.2013
comment
@SWeko: Я думаю, что имеет смысл заранее решить как можно более разумно, как реализовать определенные вещи. Мне это не кажется преждевременным, но может сэкономить много работы в будущем (по крайней мере, у меня был такой опыт).   -  person ares_games    schedule 11.01.2013


Ответы (6)


Тесты на недействительность, вероятно, будут эквивалентны простым тестам «равно 0». Они очень, очень дешевы — сотни на кадр должны быть совершенно незначительными, если у вас частота кадров не исчисляется миллионами :)

Вы должны составить профиль своего приложения, чтобы узнать, на что фактически тратится время — это намного продуктивнее, чем просто гадать. В идеале вы также должны попытаться написать несколько тестов, чтобы вы могли не только измерять текущую производительность, но и замечать, если она значительно ухудшится из-за какого-либо конкретного изменения.

person Jon Skeet    schedule 11.01.2013
comment
отличное замечание об отслеживании производительности, а не просто ее измерении время от времени - person Rune FS; 11.01.2013
comment
если эта ветвь всегда ложна или истинна, ее влияние на производительность будет значительно уменьшено за счет динамического предсказания ветвления. поэтому я никогда не стесняюсь ставить такие проверки безопасности. @ares_games - person M.kazem Akhgary; 09.01.2018

Проверка значения на null — не сложная операция, требующая проверки типов или чего-то в этом роде, и при этом не требуется выделение памяти.

Разборка оператора if (x == null) дает:

00000030  cmp         qword ptr [rsp+20h],0
00000036  jne         000000000000004A

т.е. проверка реализована как простое целочисленное сравнение значения указателя.

person Guffa    schedule 11.01.2013

Однако выполнение интенсивных проверок может привести к некоторому снижению производительности, которое может быть измерено только вашими собственными стандартами относительно вашего конкретного приложения.

В зависимости от того, в чем смысл теста, возможно, есть и другие способы быть умнее в отношении того, что и когда вы проверяете. Однако, не зная больше о вашем приложении, было бы слишком сложно попытаться придумать ответ на этот вопрос.

person James    schedule 11.01.2013
comment
Я не вижу здесь признаков интенсивных проверок. - person Jon Skeet; 11.01.2013
comment
@JonSkeet Я провожу сотни таких тестов для каждого кадра игры — я бы сказал, что это классифицируется как интенсивный в зависимости от того, сколько кадров в секунду. - person James; 11.01.2013
comment
Я не согласен. У вас есть представление, сколько работы большинство игр может выполнять за кадр? 100 очень дешевых тестов вряд ли будут значительными вообще, если только вы не ожидаете частоту кадров в сотни тысяч. Предположим, это 200 кадров в секунду. Это 20 000 проверок на недействительность в секунду. Даже на очень маломощном компьютере это не будет иметь существенного значения. - person Jon Skeet; 11.01.2013
comment
@JonSkeet 20 000 проверок недействительности в секунду (для одной небольшой части приложения) — это интенсивно, IMO — у вас явно отличается. Однако я не пишу игровые приложения, поэтому я сказал, что это может быть измерено только вашими собственными стандартами относительно вашего конкретного приложения. Я хочу сказать, что могут быть более разумные способы делать вещи. - person James; 11.01.2013

Вероятно, субъективно, но проверка на нуль эквивалентна проверке на равенство нулю и такая же быстрая. Так что я не думаю, что вам стоит беспокоиться об этом.

В равной степени - если у вас нет проблем с производительностью, зачем с этим играть.

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

Тем не менее, для условного кода потенциальное улучшение производительности (однако его необходимо будет серьезно протестировать) может заключаться в использовании делегатов для различных ветвей логики, которые устанавливаются в результате изменения одного или нескольких условий, но я бы удивлен, если такое решение действительно улучшает производительность в общем случае, особенно для вашего сценария «нуль». Итак, под этим я подразумеваю что-то вроде этого:

if([condition])
{
  Foo();
}
else
{
  Bar();
}

Если, скажем, [condition] включает локальную переменную _obj (в вашем случае _obj == null) - вы можете заменить что-то вроде этого (но будьте очень осторожны с проблемами потоковой передачи):

private Action _logic;
private object _obj;
public Object Obj {
  get { return Obj; }
  set {
    _obj=value;
    if([condition])
      _logic = () => Foo();
    else
      _logic = () => Bar();
  }
}

И теперь в любом коде, где вы ранее отметили [condition] для выполнения ветвления, вы теперь просто делаете:

_logic();

Такого рода вещи получают наибольшее количество улучшений, когда [condition] является сложным и, что особенно важно, было доказано, что занимает много процессорного времени из-за профилирования. Использование делегатов также будет нести небольшие накладные расходы по сравнению с условным переходом, но если эти накладные расходы меньше, чем выполнение [condition], то это может иметь значение, особенно если эти проверки выполняются очень часто.

Существуют и другие варианты этого, чаще всего таблицы поиска функций, полученные из значения, вместо выбора ветви кода на основе проверки на равенство (именно так могут быть реализованы большие операторы switch/case — делегаты добавляются к Dictionary с ключом проверяемое перечисление/значение - что позволяет избежать многократных проверок значения).

В конечном счете, однако, без должной осмотрительности профилирования (до и после, конечно), проведение таких оптимизаций принципиально бессмысленно.

person Andras Zoltan    schedule 11.01.2013

Никаких проблем (производительность или что-то еще) с if (x == null).

person Henrik    schedule 11.01.2013

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

person Daniel Brückner    schedule 11.01.2013