Edytować:
Dodano przykład, który można wykonać za pomocą instrukcji if-else, ale nie operatora warunkowego.
Przed odpowiedzią spójrz na [ Który jest szybszy? ] na blogu pana Lipperta. I myślę, że odpowiedź pana Ersönmeza jest tutaj najbardziej poprawna.
Próbuję wspomnieć o czymś, o czym powinniśmy pamiętać w języku programowania wysokiego poziomu.
Po pierwsze, nigdy nie słyszałem, że operator warunkowy powinien być szybszy lub równie wydajny z instrukcją if-else w C♯ .
Powód jest prosty, co jeśli nie ma operacji z instrukcją if-else:
if (i > 0)
{
value += 2;
}
else
{
}
Wymaganie operatora warunkowego jest takie, że po każdej ze stron musi być wartość , aw C♯ wymaga również, aby obie strony miały:
ten sam typ. To po prostu odróżnia ją od instrukcji if-else. W ten sposób twoje pytanie staje się pytaniem, w jaki sposób generowana jest instrukcja kodu maszynowego, aby różnicę w wydajności.
W przypadku operatora warunkowego semantycznie jest to:
Niezależnie od tego, jakie wyrażenie zostanie ocenione, istnieje wartość.
Ale z instrukcją if-else:
Jeśli wyrażenie zostanie ocenione jako prawdziwe, zrób coś; jeśli nie, zrób inną rzecz.
Wartość niekoniecznie jest związana z instrukcją if-else. Twoje założenie jest możliwe tylko przy optymalizacji.
Kolejny przykład pokazujący różnicę między nimi byłby następujący:
var array1=new[] { 1, 2, 3 };
var array2=new[] { 5, 6, 7 };
if(i>0)
array1[1]=4;
else
array2[2]=4;
powyższy kod się kompiluje, jednak zamień instrukcję if-else operatorem warunkowym po prostu nie skompiluje:
var array1=new[] { 1, 2, 3 };
var array2=new[] { 5, 6, 7 };
(i>0?array1[1]:array2[2])=4; // incorrect usage
Operator warunkowy i instrukcje if-else są pojęciowe tak samo, gdy robisz to samo, może nawet szybciej z operatorem warunkowym w C , ponieważ C jest bliżej zestawu platformy.
W podanym przez ciebie oryginalnym kodzie operator warunkowy jest używany w pętli foreach, która zepsułaby rzeczy, aby zobaczyć różnicę między nimi. Więc proponuję następujący kod:
public static class TestClass {
public static void TestConditionalOperator(int i) {
long value=0;
value+=i>0?2:3;
}
public static void TestIfElse(int i) {
long value=0;
if(i>0) {
value+=2;
}
else {
value+=3;
}
}
public static void TestMethod() {
TestConditionalOperator(0);
TestIfElse(0);
}
}
a poniżej znajdują się dwie wersje IL zoptymalizowanej i nie. Ponieważ są one długie, używam do wyświetlenia obrazu, prawa strona jest zoptymalizowana:
(Kliknij, aby zobaczyć obraz w pełnym rozmiarze).
W obu wersjach kodu IL operatora warunkowego wygląda na krótszą niż instrukcja if-else i nadal istnieją wątpliwości co do ostatecznie wygenerowanego kodu maszynowego. Poniżej przedstawiono instrukcje dotyczące obu metod, a pierwszy obraz jest niezoptymalizowany, a drugi jest zoptymalizowany:
Niezoptymalizowane instrukcje: (Kliknij, aby zobaczyć obraz w pełnym rozmiarze).
Zoptymalizowane instrukcje: (Kliknij, aby zobaczyć obraz w pełnym rozmiarze).
W tym ostatnim żółty blok jest kodem wykonywanym tylko wtedy i<=0
, a niebieski blok jest kiedy i>0
. W obu wersjach instrukcji instrukcja if-else jest krótsza.
Należy pamiętać, że dla różnych instrukcji [ CPI ] niekoniecznie jest taki sam. Logicznie, dla identycznej instrukcji, więcej instrukcji kosztuje dłuższy cykl. Jeśli jednak uwzględniony zostanie również czas pobierania instrukcji oraz pamięć podręczna / pamięć podręczna, rzeczywisty całkowity czas wykonania zależy od procesora. Procesor może również przewidywać gałęzie.
Współczesne procesory mają jeszcze więcej rdzeni, dzięki temu wszystko może być bardziej złożone. Jeśli jesteś użytkownikiem procesora Intel, możesz zajrzeć do [ Intel® 64 i IA-32 Architectures Optimization Reference Manual ].
Nie wiem, czy istniała CLR zaimplementowana sprzętowo, ale jeśli tak, prawdopodobnie przyspieszysz dzięki operatorowi warunkowemu, ponieważ IL jest oczywiście mniejsza.
Uwaga: Wszystkie kody maszynowe mają format x86.
DateTime
do pomiaru wydajności. ZastosowanieStopwatch
. Następnie czas raczej dłuższy - to bardzo krótki czas na zmierzenie.