Оператори перемикання, як правило, швидші, ніж еквівалентні операції if-else-if (як, наприклад, описано в цій статті ) завдяки оптимізаціям компілятора.
Як реально працює ця оптимізація? Хтось має гарне пояснення?
Оператори перемикання, як правило, швидші, ніж еквівалентні операції if-else-if (як, наприклад, описано в цій статті ) завдяки оптимізаціям компілятора.
Як реально працює ця оптимізація? Хтось має гарне пояснення?
Відповіді:
Компілятор може створювати таблиці стрибків, де це можливо. Наприклад, коли ви використовуєте рефлектор для перегляду виробленого коду, ви побачите, що для величезних комутаторів на рядках компілятор фактично генерує код, який використовує хеш-таблицю для їх відправлення. Хеш-таблиця використовує рядки як ключі та делегує case
коди як значення.
Це має асимптотичну кращу тривалість виконання, ніж багато ланцюгових if
тестів, і насправді швидше навіть для порівняно небагато рядків.
Це незначне спрощення, як правило, будь-який сучасний компілятор, який стикається з if..else if ..
послідовністю, яка може тривіально перетворитись на оператор переключення людиною, і компілятор. Але просто для додаткової забави компілятор не обмежений синтаксисом, тому він може генерувати "перемикання" на зразок операторів внутрішньо, які мають поєднання діапазонів, одиничних цілей тощо - і вони можуть (і робити) це робити і для переключення, і якщо. .else заяви.
Anyhoo, розширення відповіді Конрада полягає в тому, що компілятор може генерувати таблицю стрибків, але це не обов'язково гарантується (ні бажано). З різних причин таблиці стрибків роблять погані речі передбачувачам гілок сучасних процесорів, а самі таблиці погано діють, щоб кешувати поведінку, наприклад.
switch(a) { case 0: ...; break; case 1: ...; break; }
Якщо компілятор насправді створив для цього таблицю стрибків, то, ймовірно, повільніше буде if..else if..
код альтернативного стилю через прогнозування гілки таблиці переходів.
Статистика без матчу може бути недоброю.
Якщо ви фактично завантажуєте джерело, значення не збігаються, як відомо, 21, як у випадку if, так і у випадку перемикання. Компілятор повинен мати можливість абстрагуватися, знаючи, який вислів слід запускати, і центральний процесор повинен мати можливість прогнозування гілок належним чином.
Більш цікавий випадок, коли не кожен випадок розривається, на мою думку, але це, можливо, не було предметом експерименту.
Оператори перемикання / регістру можуть бути, як правило, більш швидкими на 1 рівень, але коли ви починаєте вводити в 2 або більше, заяви коммутатора / випадку починають приймати в 2-3 рази довше, ніж вкладені оператори if / else.
У цій статті є кілька порівнянь швидкості, що підкреслюють різницю швидкості, коли такі заяви є вкладеними.
Наприклад, згідно з їх тестами, зразок коду виглядає наступним чином:
if (x % 3 == 0)
if (y % 3 == 0)
total += 3;
else if (y % 3 == 1)
total += 2;
else if (y % 3 == 2)
total += 1;
else
total += 0;
else if (x % 3 == 1)
if (y % 3 == 0)
total += 3;
else if (y % 3 == 1)
total += 2;
else if (y % 3 == 2)
total += 1;
else
total += 0;
else if (x % 3 == 2)
if (y % 3 == 0)
total += 3;
else if (y % 3 == 1)
total += 2;
else if (y % 3 == 2)
total += 1;
else
total += 0;
else
if (y % 3 == 0)
total += 3;
else if (y % 3 == 1)
total += 2;
else if (y % 3 == 2)
total += 1;
else
total += 0;
завершено в половині часу, на який запустився еквівалентний вимикач / випадок:
switch (x % 3)
{
case 0:
switch (y % 3)
{
case 0: total += 3;
break;
case 1: total += 2;
break;
case 2: total += 1;
break;
default: total += 0;
break;
}
break;
case 1:
switch (y % 3)
{
case 0: total += 3;
break;
case 1: total += 2;
break;
case 2: total += 1;
break;
default: total += 0;
break;
}
break;
case 2:
switch (y % 3)
{
case 0: total += 3;
break;
case 1: total += 2;
break;
case 2: total += 1;
break;
default: total += 0;
break;
}
break;
default:
switch (y % 3)
{
case 0: total += 3;
break;
case 1: total += 2;
break;
case 2: total += 1;
break;
default: total += 0;
break;
}
break;
}
Так, це рудиментарний приклад, але він ілюструє суть.
Отже, для висновку може бути використання перемикача / випадку для простих типів, що мають глибину лише одного рівня, але для більш складних порівнянь та декількох вкладених рівнів використовують класичні конструкції if / else?