Я пишу программу с интенсивным вычислением с VB.NET 2010, и я хочу оптимизировать скорость. Я обнаружил, что операторы AndAlso
и OrElse
аномально медленны, если результат операции присваивается переменной уровня класса. Например, хотя утверждения
a = _b AndAlso _c
_a = a
взять около 6 машинных циклов между ними в скомпилированном exe, единственном утверждении
_a = _b AndAlso _c
занимает около 80 машинных циклов. Здесь _a
, _b
и _c
являются частными булевыми переменными Form1
, а рассматриваемые операторы находятся в процедуре экземпляра Form1
, из которых a
является локальной логической переменной.
Я не могу найти, почему один оператор занимает так много времени. Я изучил его с помощью NetReflector до уровня кода CIL, который выглядит хорошо:
Instruction Explanation Stack
00: ldarg.0 Push Me (ref to current inst of Form1) Me
01: ldarg.0 Push Me Me, Me
02: ldfld bool Form1::_b Pop Me, read _b and push it _b, Me
07: brfalse.s 11 Pop _b; if false, branch to 11 Me
09: ldarg.0 (_b true) Push Me Me, Me
0a: ldfld bool Form1::_c (_b true) Pop Me, read _c and push it _c, Me
0f: brtrue.s 14 (_b true) Pop _c; if true, branch to 14 Me
11: ldc.i4.0 (_b, _c not both true) Push result 0 result, Me
12: br.s 15 Jump unconditionally to 15 result, Me
-----
14: ldc.i4.1 (_b, _c both true) Push result 1 result, Me
15: stfld bool Form1::_a Pop result and Me; write result to _a (empty)
1a:
Может ли кто-нибудь пролить свет на то, почему утверждение _a = _b AndAlso _c
занимает 80 машинных циклов вместо предсказанных 5 или около того?
Я использую Windows XP с .NET 4.0 и Visual Studio Express 2010. Я измерил время с откровенно грязным фрагментом, который в основном использует объект Секундомер во время цикла For-Next с 1000 итерациями, содержащими код в вопросе и сравнить его с пустым циклом For-Next; он включает в себя одну бесполезную инструкцию в обеих циклах, чтобы тратить несколько циклов и предотвращать срыв процессора. Грубый, но достаточно хороший для моих целей.