Wie können wir herausfinden? Werfen wir nur einen Blick auf den generierten Code.
Hier ist ein Testprogramm:
internal static class Program
{
public static int MaxA(int value, int max)
{
return value > max ? max : value;
}
public static int MaxB(int value, int max)
{
if (value > max)
return max;
else
return value;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static int TestA(int a, int b)
{
return MaxA(a, b);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static int TestB(int a, int b)
{
return MaxB(a, b);
}
private static void Main()
{
var rand = new Random();
var a = rand.Next();
var b = rand.Next();
var result = TestA(a, b);
Console.WriteLine(result);
result = TestB(a, b);
Console.WriteLine(result);
}
}
Zuerst lassen Sie uns einige Dinge klarstellen. In einer Veröffentlichung bauen, die IL von MaxA
ist (auf Roslyn):
.method public hidebysig static
int32 MaxA (
int32 'value',
int32 max
) cil managed
{
// Method begins at RVA 0x2050
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: bgt.s IL_0006
IL_0004: ldarg.0
IL_0005: ret
IL_0006: ldarg.1
IL_0007: ret
} // end of method Program::MaxA
Für MaxB
, es ist:
.method public hidebysig static
int32 MaxB (
int32 'value',
int32 max
) cil managed
{
// Method begins at RVA 0x2059
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: ble.s IL_0006
IL_0004: ldarg.1
IL_0005: ret
IL_0006: ldarg.0
IL_0007: ret
} // end of method Program::MaxB
So ist die IL ist symmetrisch für beide Funktionen (es ist der gleiche Code, außer dass die Reihenfolge der Zweige sowie der Verzweigungsbefehl invertiert sind).
Jetzt überprüfen wir, wie der x64-Code von TestA
und TestB
aussieht.
TestA
, x64, RyuJIT:
return MaxA(a, b);
00007FFED5F94530 cmp ecx,edx
00007FFED5F94532 jg 00007FFED5F94538
00007FFED5F94534 mov eax,ecx
00007FFED5F94536 jmp 00007FFED5F9453A
00007FFED5F94538 mov eax,edx
00007FFED5F9453A ret
Sie können sehen, dass die MaxA
Funktion inlined ist (es gibt keine call
Anweisung und Sie können die jg
"springen, wenn mehr" Verzweigungsanweisung deutlich zu sehen).
TestB
, x64:
return MaxB(a, b);
00007FFED5F94550 cmp ecx,edx
00007FFED5F94552 jle 00007FFED5F94558
00007FFED5F94554 mov eax,edx
00007FFED5F94556 jmp 00007FFED5F9455A
00007FFED5F94558 mov eax,ecx
00007FFED5F9455A ret
Es überrascht nicht, bekommen wir das gleiche Ergebnis.
Für compelteness, hier MaxA
auf x86:
return MaxA(a, b);
00A32E22 in al,dx
00A32E23 cmp ecx,edx
00A32E25 jg 00A32E2B
00A32E27 mov eax,ecx
00A32E29 jmp 00A32E2D
00A32E2B mov eax,edx
00A32E2D pop ebp
00A32E2E ret
Inlined auch. (Debug -> Fenster -> Demontage)
Als Referenz können Sie den erzeugten Assembler-Code mit dem Zerlegen Fenster überprüfen, wenn Sie auf einem Breakpoint sind, aber zuerst sicher, dass Sie die Suppress JIT deaktivieren machen Optimierung auf Modullast Option:
„Inlining“ ist ein Begriff, zu dem, was mit einem * Verfahren * Optimierer tut der Jitter gilt. Der?: -Operator ist keine Methode, der Maschinencode dafür wird immer "in der Zeile" generiert, auch im nicht optimierten Debug-Build. –
Ihre Max-Methode? Sicher, es ist sehr klein und macht nichts icky, das der Optimierer nicht mag. Sie müssen den Titel Ihrer Frage korrigieren. –
@Krythic Ich stimme Hans zu, du Titel ist ein bisschen irreführend. Es klingt so, als würden Sie fragen, ob der '?:' - Operator selbst inline ist und nicht die Methoden, die '?:' Enthalten, inline sind, was Ihre eigentliche Frage ist. –