Оптимизация операторов if путем изменения порядка - PullRequest
2 голосов
/ 05 января 2009

Я помню, как однажды прочитал, что порядок членов оценки важен. Такие как

if (null == myClass)

лучше (быстрее?), Чем

if (myClass == null)

это тот случай? Если так, может кто-нибудь объяснить, как и почему? Если для ответа требуется язык, тогда стремитесь к c #.
Спасибо

Ответы [ 8 ]

24 голосов
/ 05 января 2009

Нет, это не быстрее. Это реликт со старых времен C, он избегал ошибок типа

if(myClass = null) /* accident, sets myClass to null instead of comparing */

чтобы у вас всегда была постоянная слева:

if(null = myClass) /* throws an error at compile time */

Однако нет смысла делать это в C #, я думаю ..

6 голосов
/ 05 января 2009

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

if ((a != null) && (someLongCheck()) ...

и значение равно нулю, тогда someLongCheck() не будет вызываться.

5 голосов
/ 05 января 2009

Ну, это полностью зависит от языка и компилятора. Использование компилятора C #, поставляемого с фреймворком, не имеет значения, так как вывод IL одинаков. Вот пример рутины:

static void Main(string[] args)
{
    // Create the instance.
    MyClass instance = new MyClass();

    if (null == instance)
    {
    }

    if (instance == null)
    {
    }
}

IL для первого сравнения выглядит следующим образом:

L_0007: ldnull 
L_0008: ldloc.0 
L_0009: ceq 
L_000b: ldc.i4.0 
L_000c: ceq 
L_000e: stloc.1 
L_000f: ldloc.1 
L_0010: brtrue.s L_0014
L_0012: nop 
L_0013: nop

И второе:

L_0014: ldloc.0 
L_0015: ldnull 
L_0016: ceq 
L_0018: ldc.i4.0 
L_0019: ceq 
L_001b: stloc.1 
L_001c: ldloc.1 
L_001d: brtrue.s L_0021
L_001f: nop 
L_0020: nop

Как видите, выходные данные практически идентичны, за исключением порядка элементов в стеке. Операции такие же.

Как упоминалось ранее, это реликвия из старых дней C, где все, что имеет значение 0, оценивается как ложное, и если вы пропустили знак равенства, присвоение было оценено как условное.

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

4 голосов
/ 05 января 2009

Я помню, как однажды прочитал, что заказ членов оценки важно.

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

Поскольку операторы && и || перегружены, вы можете настроить код для большей производительности, используя следующие рекомендации:

  • При использовании && закажите ваши условия так, чтобы условие, наиболее вероятное неудачное, было на первом месте.
  • При использовании || закажите ваши условия так, чтобы условие, наиболее вероятное для успеха, было на первом месте.

Допустим, ваша компания требует, чтобы вы генерировали отчеты TPS каждый понедельник, вы можете написать такой код:

Образец № 1:

if (DateTime.Today.DayOfWeek == DayOfWeek.Monday
    && !Database.TpsReportsExist())
{
    // create TpsReports
}

Образец № 2:

if (!Database.TpsReportsExist()
    && DateTime.Today.DayOfWeek == DayOfWeek.Monday)
{
    // create TpsReports
}

Образцы 1 и 2 эквивалентны, но образец # 2 выполняет запрос к базе данных независимо от того, какой это день недели. Пример № 1 позволяет избежать ненужного попадания в базу данных, поэтому мы экономим несколько циклов ЦП и время выполнения.

Приведенный выше пример является тривиальным, но он может сильно повлиять на производительность, если вы выполняете этот вид кода в узком цикле.

3 голосов
/ 05 января 2009

Это не будет быстрее, если твой компилятор действительно тупой.

Это значит, что если вы случайно напечатаете = not ==, вы получите ошибку компиляции, откуда, как я полагаю, возникла эта идиома.

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

   if (myClass ==  null)
1 голос
/ 05 января 2009

Насколько я знаю, первая запись написана лучше, чем вторая, не с целью повышения производительности, а во избежание распространенной ошибки в дочерних языках C и C:

Если вы поместите константу слева от ==, а переменную справа, компилятор обнаружит, если вы ввели = вместо ==.

Конечно, это не работает при сравнении двух переменных.

1 голос
/ 05 января 2009

Нет, это не имеет значения. Помещение литерала в левую часть было старым приемом программирования на C / C ++, позволяющим избежать боли при случайном вводе = вместо ==. Поскольку литерал не является lvalue, вы получите ошибку компиляции, если ошибетесь.

0 голосов
/ 05 января 2009

Порядок предметов в индивидуальной оценке, такой как вы спрашиваете, не имеет значения. Код все еще должен разрешать обе стороны утверждения, чтобы определить равенство или неравенство.

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

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