2015-01-07 2 views
2

Выполняется ли в C# все операторы if перед выполнением, чтобы в случае, если оператор if не может быть правдой (до подтверждения всех условий), будет отменен?Анализ if-операторов для оптимизации производительности

Моя проблема в том, что я хочу избавиться от нескольких операторов if, потому что некоторые методы в операторе if требуют долгого выполнения (что теряется впустую, если они были выполнены).

Вот простой оператор if (здесь он работает). Но насколько это хорошо на сложных заявлениях?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace IfTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      if (true || NeedALongTime()) 
      { 
       Console.WriteLine("!"); 
      } 

      Console.ReadLine(); 
     } 

     private static bool NeedALongTime() 
     { 
      Thread.Sleep(10000); 

      return true; 
     } 
    } 
} 
+1

Нет, они не все оцениваются для булевых выражений с '&&' и '||' (Google о _short-circuit_). Вот почему вы можете написать 'if (obj! = Null && obj.Value == someValue)'. Более того, если выражение можно определить и оно будет постоянным во время компиляции, тогда сам компилятор _may_ оптимизирует (в режиме освобождения) этот код (но вы также должны получить предупреждение для этого). –

+0

И как общее утверждение, лучший способ справиться с производительностью - написать четкий, продуманный код и установить показатели производительности * *.Затем вы измеряете производительность того, что вы написали, и, если это достаточно хорошо, вы просто переходите к следующей задаче. Вы * не * хорошо пишете код, создавая список тысяч «правил» о «Я должен писать все операторы if if, такие как * this *» и т. Д. –

+0

Он уже работает таким образом, весь if() оператор удаляется, и остается только вызов Console.WriteLine(). Конечно, вы никогда не заметите, что он работает на наносекунду быстрее. Пятая пуля в [этот пост] (http://stackoverflow.com/a/4045073/17034). –

ответ

1

Метод NeedALongTime никогда не будет называться. C# перестает оценивать логическое выражение, как только оно сможет определить результат.

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

Языки, подобные C# и C++, используют короткое замыкание, в то время как другие, такие как VB.NET, этого не делают.

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

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

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

+0

Спасибо за ваш ответ. Один вопрос: «Языки, такие как C# и C++, используют короткое замыкание, в то время как другие, такие как VB.NET, не являются». Я думал, что каркас .net выполняет эту работу, а не C#/VB.Net в целом. – BendEg

+1

Нет, каждый язык использует свою собственную семантику. Можно сказать, что процессор выполняет эту работу, но это тоже не так. Булево выражение имеет только два аргумента. Сложное логическое выражение представляет собой комбинацию булевых выражений, оцененных в порядке и семантике, определенных конкретным языком. –

+1

Я не согласен с * Вы должны быть осторожны при использовании короткого замыкания *. Я не забочусь о других языках, когда я пишу код 'C# 'и в' C# 'short-circuiting - это прекрасный способ объединить выполнение логики в условие, чтобы избежать деревьев' if'. Очень легко следовать, например: if (CheckA || CheckB && CheckC) DoSomething(); ', где вы знаете, что' CheckA' (это будет код или метод настройки свойств) будет всегда, но 'CheckB 'будет происходить только в том случае, если' CheckA' не сработает, 'CheckC', только если' CheckB' не выйдет из строя (но 'CheckA') и' DoSomething' вызов (и логика вызова) не затенен. – Sinatr

3

Оценочная модель для булевых операторов && и || четко определена. Второй операнд оценивается только в том случае, если ответ не может быть получен из первого операнда.

Это называется короткое замыкание. Это гарантированное поведение.

Это не оптимизация компилятора или JIT.

Вы можете положиться на это, но, на мой взгляд, он делает для хрупкого и подверженного ошибкам код, чтобы сделать это по соображениям производительности. Для будущих сопровождающих может быть непонятным, почему порядок оценки имеет, чтобы быть таким образом, хотя, похоже, нет очевидных зависимостей. Может быть, вы можете использовать Lazy<T>, чтобы получить ленивую оценку ?!

+1

О, 'Lazy' - очень интересная вещь, спасибо! – BendEg

+0

@BendEg, тогда, я уточню: вы можете настроить один Lazy для каждого дорогостоящего вычисления, которое может потребоваться для запуска. Они могут ссылаться друг на друга (поэтому они образуют DAG зависимостей). Таким образом, вы можете автоматически писать свои операторы if и другие вычисления автоматически. – usr