2009-04-20 14 views
274

Powiel możliwe:
Is there any significant difference between using if/else and switch-case in C#?Czy "else if" jest szybsze niż "przypadek switch()"?

jestem ex facet Pascal, obecnie nauka C#. Moje pytanie jest następujące:

Czy poniższy kod jest szybszy niż zmiana?

int a = 5; 

if (a == 1) 
{ 
    .... 
} 
else if(a == 2) 
{ 
    .... 
} 
else if(a == 3) 
{ 
    .... 
} 
else if(a == 4) 
{ 
    .... 
} 
else 
    .... 

i przełącznik:

int a = 5; 

switch(a) 
{ 
    case 1: 
     ... 
     break; 

    case 2: 
     ... 
     break; 

    case 3: 
     ... 
     break; 

    case 4: 
     ... 
     break; 

    default: 
     ... 
     break; 


} 

Który jest szybszy?

Pytam, ponieważ mój program ma podobną strukturę (wiele, wiele instrukcji "else if"). Czy powinienem zmienić je w przełączniki?

+65

Czuję się zobowiązany zauważyć, że możesz nie być w pełni wykorzystany w twoich projektach polimorfizmów, jeśli twój kod ma wiele takich struktur. –

+4

Zobacz http://stackoverflow.com/questions/445067/if-vs-switch-speed –

+0

Przełącznik jest szybszy, ale jeśli nie masz hiperoptymalizacji ciasnej pętli, to nic nie znaczy. Co to jest 37 nanosekund w porównaniu z 42 nanosekundami (wykonane liczby)? –

Odpowiedz

466

Dla zaledwie kilku pozycji różnica jest niewielka. Jeśli masz wiele przedmiotów, zdecydowanie powinieneś użyć przełącznika.

Jeśli przełącznik zawiera więcej niż pięć elementów, jest zaimplementowany przy użyciu tabeli odnośników lub listy mieszającej. Oznacza to, że wszystkie przedmioty mają ten sam czas dostępu, w porównaniu do listy, jeśli: s, gdzie ostatni element zajmuje znacznie więcej czasu, ponieważ musi najpierw ocenić każdy poprzedni warunek.

+75

Prawda, ale z łańcuchem "If-else-if" możesz zamówić warunki na podstawie prawdopodobieństwa, że ​​są prawdziwe. –

+58

Tak, ale pierwsze 4-5 przypadków musi złapać bardzo blisko 100% wystąpień, aby nadrobić te, które są wolniejsze. – Guffa

+21

Czy większość współczesnych kompilatorów nie powinna optymalizować głęboko, jeśli/else if/else if/else, jeśli decyzja wskazuje na tablicę przełączników/skoków? To znaczy; to nie powinno mieć znaczenia, kompilator je zoptymalizuje, dlaczego nie po prostu napisać najbardziej czytelny kod? –

5

Nie powinno być trudno przetestować, utwórz funkcję, która przełącza lub ifelse jest pomiędzy 5 liczbami, rzuć rand (1,5) do tej funkcji i zapętlaj ją kilka razy, jednocześnie ustawiając czas.

3

Technicznie, dają dokładnie taki sam wynik, więc powinny być zoptymalizowane w prawie taki sam sposób. Istnieje jednak większa szansa, że ​​kompilator zoptymalizuje skrzynkę przełączników za pomocą tabeli przeskoku niż ifs.

Mówię tutaj o ogólnej sprawie. W przypadku 5 wpisów średnia liczba testów przeprowadzonych dla przypadków if powinna być mniejsza niż 2,5, zakładając, że warunki są ustalane według częstotliwości. Nie jest to wąskie gardło, o którym można by pisać do domu, chyba że w bardzo trudnej pętli.

5

Przełącznik jest zwykle szybszy niż długa lista znaków ifs, ponieważ kompilator może wygenerować tabelę przeskoku. Im dłuższa lista, tym lepiej instrukcja switch jest nad serią instrukcji if.

+2

Noet, który dotyczy tylko tabeli skoku (IIRC) dla wartości sąsiednich. Nierzadko zdarza się, że kompilator emituje mieszankę tabel z parametrami skoku i parametrami dla złożonych, nieciągłych opcji. –

19

Wierząc w this performance evaluation, obudowa przełącznika jest szybsza.

Taka jest konkluzja:

Wyniki pokazują, że instrukcja switch jest szybsze wykonanie niż if-else-if drabiny. Wynika to ze zdolności kompilatora do optymalizacji instrukcji switch. W przypadku drabiny if-else-if kod musi przetwarzać każdą instrukcję if w kolejności określonej przez programistę. Ponieważ jednak każdy przypadek w instrukcji switch nie polega na wcześniejszych przypadkach, kompilator jest w stanie zmienić kolejność testowania w taki sposób, aby zapewnić najszybszą realizację.

3

switch zwykle jest tłumaczony na tabelę odnośników przez kompilator, jeśli to możliwe. Tak więc szukanie przypadkowego przypadku jest O (1), zamiast faktycznie robić kilka porównań przypadku, zanim znajdziesz ten, który chcesz.

Tak więc w wielu przypadkach łańcuch if/else if będzie wolniejszy.Zależnie od częstotliwości, z jaką trafiają twoje skrzynie, nie ma to znaczenia.

2

Krótka odpowiedź: switch jest szybsza

if potrzebujesz dwóch porównań (przy prowadzeniu przykładowy kod) średnio dostać się do właściwej klauzuli.

Instrukcja switch średnia liczba porównań będzie taka sama, niezależnie od tego, ile masz różnych przypadków. Kompilator/VM wykona "tabelę odnośników" możliwych opcji podczas kompilacji.

Czy maszyny wirtualne mogą zoptymalizować instrukcję if w podobny sposób, jeśli często uruchamiasz ten kod?

11

Kolejna rzecz do rozważenia: czy to naprawdę wąskie gardło Twojej aplikacji? Są bardzo rzadkie przypadki, kiedy taka optymalizacja jest naprawdę wymagana. W większości przypadków można uzyskać lepsze przyspieszenia, przemyślając algorytmy i struktury danych.

4

Znacznie ważniejsze niż zalety przełącznika (które są względnie niewielkie, ale warte zauważenia) są problemy z czytelnością.

Dla jednego znajduję instrukcję przełączającą bardzo wyraźną w umyśle i czystą białą, w porównaniu do łańcuchów znaków if.

147

Dlaczego cię to obchodzi?

99,99% czasu, nie powinieneś się przejmować.

Tego rodzaju mikro-optymalizacje prawdopodobnie nie wpłyną na wydajność kodu.

Ponadto, jeśli potrzebujesz opieki, powinieneś robić profilowanie wydajności na swoim kodzie. W takim przypadku ustalenie różnicy w wydajności między skrzynką przełączników a blokiem if-else byłoby banalne.

Edytuj: Dla jasności: zastosuj dowolny projekt, który jest bardziej przejrzysty i łatwiejszy do utrzymania. Zwykle, gdy mamy do czynienia z ogromną skrzynką przełączników lub blokiem-else rozwiązaniem jest użycie polimorfizmu. Znajdź zachowanie, które się zmienia i obuduj je. Musiałem poradzić sobie z ogromnym, brzydkim kodem przełącznika tak jak wcześniej i generalnie nie jest to takie trudne do uproszczenia. Ale tak satysfakcjonujące.

+45

Myślę, że w 100% przypadków nie powinieneś się przejmować. – Naveen

+78

Absolutnie się nie zgadzam. Zdecydowanie powinieneś zawsze się tym przejmować, nie tyle ze względu na wydajność, ale wpływa to również na czytelność kodu i łatwość konserwacji. I, jak wspomnieli inni, dobrze pomyślicie o lepszym wykorzystaniu polimorfizmu. –

+5

Och, zgadzam się, że należy zawsze dbać o czytelność i łatwość konserwacji. Właściwym sposobem na przepisanie ogromnego przełącznika/bloku obudowy jest prawdopodobnie polimorfizm (który, nawiasem mówiąc, jest prawdopodobnie nieco wolniejszy, ale nie powinno Cię to obchodzić). Makro-optymalizacja (dobry projekt) jest zawsze lepsza niż mikro-optymalizacja (szybsze stwierdzenia). – Wedge

1

Ponieważ oświadczenie switch wyraża tę samą intencję jako łańcucha if/else ale w bardziej ograniczonym, formalny sposób, pierwsze przypuszczenie powinno być to, że kompilator będzie mógł zoptymalizować go lepiej, ponieważ może wyciągnąć więcej wniosków o warunki umieszczone na twoim kodzie (tj. tylko jeden stan może być prawdą, porównywana wartość jest typem pierwotnym itp.) Jest to całkiem bezpieczna ogólna prawda, gdy porównujesz dwie podobne struktury językowe dla wydajności środowiska wykonawczego.

4

Nie jestem pewien, ale wierzę, że prędkość jednej lub drugiej zmiany zmienia się w zależności od języka programowania, z którego korzystasz.

Zazwyczaj wolę używać przełącznika.W ten sposób kod jest prosty do odczytania.