co będzie efektywniejsze w końcowym wyniku?
taki kod
static bool JakisWarunek()
{
return "asd".Length==3;
}
static void test()
{
string s = "ala ma kota";
// 1 przypadek
while (JakisWarunek())
{
int i = s.Length;
i++;
}
// 2 przypadek
int j;
while (JakisWarunek())
{
j = s.Length;
j++;
}
}
kompiluje się do czegoś takiego (komentarze moje)
00000000 push ebp
00000001 mov ebp,esp
00000003 push esi
00000004 mov esi,dword ptr ds:[02C72088h] ; string s = "ala ma kota";
0000000a call dword ptr ds:[00149C54h] ; JakisWarunek()
00000010 test eax,eax
00000012 je 00000024
00000014 cmp dword ptr [esi+8],eax ; WTF
00000017 cmp dword ptr [esi+8],eax ; WTF
0000001a call dword ptr ds:[00149C54h] ; JakisWarunek()
00000020 test eax,eax
00000022 jne 00000017
00000024 call dword ptr ds:[00149C54h] ; JakisWarunek()
0000002a test eax,eax
0000002c je 0000003E
0000002e cmp dword ptr [esi+8],eax ; WTF
00000031 cmp dword ptr [esi+8],eax ; WTF
00000034 call dword ptr ds:[00149C54h] ; JakisWarunek()
0000003a test eax,eax
0000003c jne 00000031
0000003e pop esi
0000003f pop ebp
00000040 ret
widzimy, że obie zmienne jako nieistotne dla działania programu wyleciały, są tu jakieś nic nie robiące instrukcje cmp
, będące „wywołaniem” metody Length()
, tak czy inaczej obie pętle wyglądają identycznie.
wniosek: obie zmienne nie istnieją, bo optymalizator je (nie do końca) wyciął. Ale dodajmy tam wyświetlanie:
while (JakisWarunek())
{
int i = s.Length;
i++;
Console.WriteLine(i);
}
// 2 przypadek
int j;
while (JakisWarunek())
{
j = s.Length;
j++;
Console.WriteLine(j);
}
o, teraz mamy pełne pętle:
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 mov edi,dword ptr ds:[02A92088h]
0000000b mov eax,dword ptr ds:[02A9208Ch]
00000011 cmp dword ptr [eax+8],3
00000015 jne 0000003B
00000017 cmp dword ptr [edi+8],eax
0000001a mov esi,dword ptr [edi+8]
0000001d inc esi
0000001e call 6C87BE90 ; WriteLine(i)
00000023 mov ecx,eax
00000025 mov edx,esi
00000027 mov eax,dword ptr [ecx]
00000029 call dword ptr [eax+000000BCh]
0000002f mov eax,dword ptr ds:[02A9208Ch]
00000035 cmp dword ptr [eax+8],3
00000039 je 0000001A
0000003b mov eax,dword ptr ds:[02A9208Ch]
00000041 cmp dword ptr [eax+8],3
00000045 jne 0000006B
00000047 cmp dword ptr [edi+8],eax
0000004a mov esi,dword ptr [edi+8]
0000004d inc esi
0000004e call 6C87BE90 ; WriteLine(i)
00000053 mov ecx,eax
00000055 mov edx,esi
00000057 mov eax,dword ptr [ecx]
00000059 call dword ptr [eax+000000BCh]
0000005f mov eax,dword ptr ds:[02A9208Ch]
00000065 cmp dword ptr [eax+8],3
00000069 je 0000004A
0000006b pop esi
0000006c pop edi
0000006d pop ebp
0000006e ret
znowu jest tu parę instrukcji zbędnych (dlatego programy w C# są ogólnie wolniejsze niż natywne np. w C++) ale nadal obie pętle są identyczne.
Nie ma więc znaczenia dla prędkości, którego wariantu użyjemy.
PS. podobno 64-bitowy Framework ma lepszy optymalizator kodu maszynowego, ale nie mam jak sprawdzić.