JIT простая оптимизация

У меня есть следующий метод

void DoSome(){
    if (int.Parse(SomeStringProperty) > 8)
        // do something

    if (int.Parse(SomeStringProperty) < 10)
        // do something
}

Знает ли JIT, что нужно сохранить проанализированное значение, или лучше сделать следующее:

void DoSome(){
    var x = int.Parse(SomeStringProperty);
    if (x > 8)
        // do something

    if (x < 10)
        // do something
}

Здесь я вижу две оптимизации:

  1. JIT автоматически сделает что-то вроде второго примера.
  2. JIT выполняет одну оптимизацию и кэширует результат

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

Короче говоря, когда я пишу приложение на С#, какой из приведенных выше примеров предпочтительнее?

Обновить

Если ответа нет, то почему он отличается от этого:

foreach (var x in MyMethod.GetEnumeration())

здесь не нужно делать:

var lst = MyMethod.GetEnumeration();
foreach (var x in lst)

person Maya    schedule 02.12.2013    source источник
comment
Я почти уверен, что это не так. В общем, это не оптимизирует вызовы сложных функций. int.Parse даже не является чистым в самом строгом смысле, поскольку он обращается к глобальному изменяемому состоянию, связанному с текущей культурой.   -  person CodesInChaos    schedule 02.12.2013
comment
Во втором случае вам нужно var x = int.Parse(SomeStringProperty);. Исправьте и используйте эту опцию - вы никогда не можете быть уверены с JIT (это зависит от платформы и фазы Луны)   -  person Sergey Berezovskiy    schedule 02.12.2013
comment
Я обычно предпочитаю второй подход, потому что он не вызывает функцию, и в любом случае это разбор строки (String = Slow почти в каждом случае (особенно если она длинная)). Я не уверен, что JIT оптимизирует его, но я не думаю (как он может управлять многопоточностью? Сохранить последнее изменение? Немного проверить?).   -  person Marco Acierno    schedule 02.12.2013
comment
@lazyberezovsky Я согласен с фазой Луны JIT, но я думал, что первая оптимизация должна быть последовательной. в любом случае, вероятно, я воспользуюсь вторым вариантом   -  person Maya    schedule 02.12.2013
comment
@MarcoLopezAcierno, это правда, потому что JIT выполняет оптимизацию также в многопоточном случае. см. здесь: albahari.com/threading/part4.aspx   -  person Maya    schedule 02.12.2013


Ответы (2)


В общем случае нет. Потому что: побочные эффекты. В общем, any.Method(args) может каждый раз делать что-то новое (регистрация, случайный выбор, увеличение счетчиков, подключение к внешнему неуправляемому ресурсу и т. д.) и должен вызываться каждый раз, чтобы сохранить исходную семантику. Может быть, что поддерживается белый список "чистых" функций, но я не вижу особых причин для включения в него int.Parse.

По сути, если вы хотите поднять его: поднимите его сами. Код во втором примере разумен (лично я бы добавил else, то есть else if).


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

Наконец, в многопоточном мире само поле могло измениться.

person Marc Gravell    schedule 02.12.2013
comment
И простой тест с циклом for показывает, что на данный момент в моем .NET JIT код не оптимизирован, даже если вы используете строковый литерал. Итак, int.Parse не совсем медленный, но он намного медленнее, чем сравнение. Особенно, если значение x хранится в регистре, а не в оперативной памяти. - person Luaan; 02.12.2013
comment
@Марк, спасибо за ответ. пожалуйста, взгляните на мое обновление q. - person Maya; 02.12.2013
comment
@Marc, мой пример не так хорош ... это не настоящий метод, и я понимаю, что вы имеете в виду, но я спрашиваю в общем случае. скажем, SomePropertyString не изменится, и даже если он изменится, мне все равно. и скажем, что нет оператора if, а есть только два вызова для int.Parse() - person Maya; 02.12.2013
comment
@Marc Наконец, в многопоточном мире само поле могло измениться. да, но обратите внимание, что JIT оптимизируется даже в многопоточном мире: albahari.com/threading/part4. aspx - person Maya; 02.12.2013
comment
@Майя действительно; но это относится только к доступу к полю; вы вызываете несколько методов - они все равно должны быть вызваны; теперь они могут быть встроены, но: тогда они будут встроены в обоих местах - person Marc Gravell; 02.12.2013

Об обновлении: этот пример совершенно не связан. Вы также можете привести пример:

var val = MyMethod.SomeMethod();

и сравните его с:

var tmp = MyMethod.SomeMethod();
var val = tmp;

в обоих случаях все, что вы сделали, это отделили вызов/оценку от использования путем присваивания промежуточной переменной. И в обоих случаях, если мы предположим, что переменная lst / tmp больше нигде не используется, мы можем быть достаточно уверены, что компилятор (не JIT) в любом случае действительно удалит эту переменную, так что они не просто логически эквивалентны — они фактически эквивалентны. В этом сценарии мы не удаляли никаких вызовов методов и т. д. — мы оцениваем их только один раз. Совершенно не связанный сценарий.

person Marc Gravell    schedule 02.12.2013
comment
еще раз спасибо. и да, конечно, оптимизация времени компиляции. Кстати, в примере foreach, если я использую временную переменную, которую я использую позже в методе, а в foreach я вызываю явный метод, правильно ли я понимаю, что никакой оптимизации не произойдет? надеюсь меня поняли... - person Maya; 02.12.2013