Как я могу проверить, была ли функция кэширована в C #? - PullRequest
0 голосов
/ 21 марта 2011

Я создал следующие функции в C #:

float GetPI()
{
  return 22.0f/7.0f;
}

void Calculate()
{
  float f1 = GetPI()*4;
  float f2 = GetPI()*5;
}

Если я создаю сборку релиза, как я смогу проверить, будет ли JIT-компилятор кэшировать вычисление 22/7 или оно будет вычисляться при каждом вызове функции GetPI?

PS: у меня нет профессиональной версии C # studio

РЕДАКТИРОВАТЬ: изменил 22/7 на 22.0f / 7.0f, чтобы сделать пример функции более точным

Ответы [ 3 ]

4 голосов
/ 21 марта 2011

Я не уверен, что вы подразумеваете под кэшированием.Если компилятор не выполняет постоянное свертывание (что в этом случае будет) или среда выполнения не встроит вашу функцию (что, вероятно, в этом случае), он не будет автоматически выполнять никакого «кэширования» для вас.


Выражение 22f/7f является константным выражением и может быть оценено во время компиляции (иначе, постоянное сворачивание ).Таким образом, в скомпилированной сборке он будет выглядеть так:

float GetPI()
{
  return 3.142857f; // however many digits of precision
}

Компилятор всегда будет выполнять этот вид оптимизации, если будет предоставлена ​​такая возможность.Если нет опции компилятора, чтобы отключить это (что я не уверен, что есть).Чтобы убедиться в этом, вы можете использовать Reflector (как уже указывали другие), чтобы увидеть скомпилированную сборку.Вы должны увидеть, что он действительно делает это, независимо от того, является ли это отладкой или сборкой Release или с использованием экспресс-версий (если эта оптимизация явно не отключена).


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


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


Если вы хотите получить абсолютную гарантию, что компилятор "кеширует" (как в случае не пересчитать частное) значение, вы должны объявить свое значение как константу (или использовать существующую и более точную System.Math.PI константу).Во время выполнения ничего не определяется, все известно во время компиляции.И каждый раз, когда вы используете это значение, оно будет «встроенным», так что вам не придется об этом беспокоиться.

const float PI = 22f / 7f; // will be stored as 3.142857f

// or another way, if you need PI to be a float but want a more accurate value
const float PI = (float)Math.PI; // will store as much precision possible
// note that this only works because Math.PI is declared as a constant
1 голос
/ 21 марта 2011

Есть много способов.Одним из удобных является использование .NET Reflector.

Откройте сборку в Reflector, выберите C #, найдите метод в древовидном меню, выберите Инструменты / Разборка.Дизассемблер покажет что-то вроде следующего:

public float GetPI()
{
    return 3f;
} 
1 голос
/ 21 марта 2011

Загрузите и установите .NET Reflector (первоначально написанный Lutz Roeder, а теперь поддерживаемый Red Gate).Возможно, вам придется искать более старую версию, если вы не хотите платить.

Когда вы открываете свой код в Reflector, вы можете увидеть, какие изменения внес компилятор.

Это не будетЧтобы показать вам JIT-оптимизацию, для этого вам нужно пройтись по машинному коду в отладчике, но я уверен, что этот случай будет оценен компилятором C #.

...