Если еще быстрее, чем в случае switch ()?

Я бывший парень Pascal, в настоящее время изучаю C #. У меня такой вопрос:

Код ниже быстрее, чем переключение?

int a = 5;

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

И переключатель:

int a = 5;

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

    case 2:
        ...
        break;

    case 3:
        ...
        break;

    case 4:
        ...
        break;

    default:
        ...
        break;


}

Какой из них быстрее?

Я спрашиваю, потому что моя программа имеет аналогичную структуру (много-много операторов «else if»). Должен ли я превратить их в переключатели?


person Ivan Prodanov    schedule 20.04.2009    source источник
comment
Я вынужден отметить, что вы можете недостаточно использовать полиморфизм в своих проектах, если в вашем коде много таких структур.   -  person Greg D    schedule 20.04.2009
comment
См. stackoverflow.com/questions/445067/if-vs-switch-speed   -  person Dirk Vollmar    schedule 20.04.2009
comment
Switch работает быстрее, но если вы не гипероптимизируете жесткий цикл, это ничего не значит. Что такое 37 наносекунд против 42 наносекунд (составленные числа)?   -  person Chris Marisic    schedule 05.05.2016
comment
Интересно, как это отличается при использовании логики на уровне случая, например (псевдо) switch(true) case a==0; case a>0; case a<0; и т. Д.   -  person Jacksonkr    schedule 19.10.2017
comment
@Jacksonkr Java не позволяет включать значения типа boolean. Кроме того, выражения case должны быть постоянными.   -  person Kröw    schedule 28.06.2019
comment
@GregD Не могли бы вы расширить этот комментарий? Я знаю, что такое полиморфизм как концепция, но мало практикуюсь с ним. Как бы вы использовали это, чтобы помочь в этой ситуации?   -  person rocksNwaves    schedule 05.05.2021


Ответы (14)


Всего по нескольким позициям разница небольшая. Если у вас много предметов, вам обязательно стоит использовать переключатель.

Если переключатель содержит более пяти элементов, он реализуется с помощью таблицы поиска или хеш-списка. Это означает, что все элементы получают одинаковое время доступа по сравнению со списком if: s, где до последнего элемента требуется гораздо больше времени, поскольку он должен сначала оценить каждое предыдущее условие.

person Guffa    schedule 20.04.2009
comment
Верно, но с цепочкой if-else-if вы можете упорядочить условия в зависимости от того, насколько вероятно, что они будут истинными. - person Dave Van den Eynde; 20.04.2009
comment
Да, но первые 4-5 случаев должны улавливать почти 100% случаев, чтобы компенсировать более медленные. - person Guffa; 20.04.2009
comment
Разве большинству современных компиляторов не следует проводить глубокую оптимизацию if / else if / else if / else if, если решение указывает на таблицу переключения / перехода? Что сказать; это не имеет значения, компилятор оптимизирует это, почему бы просто не написать максимально читаемый код? - person Dean J; 02.08.2010
comment
@ Дин Дж .: Да, обычно вы должны писать максимально читаемый код, даже если производительность несколько отличается. Если вам нужно оптимизировать код, это все равно может иметь значение. Чтобы компилятор оптимизировал код описанным вами способом, он должен иметь больше знаний о значении, то есть знать, имеет ли многократное чтение значения какие-либо побочные эффекты, поскольку изменение кода на переключатель приведет к считыванию значения только один раз. - person Guffa; 02.08.2010
comment
С моей точки зрения, switch намного читабельнее, чем цепочка if-elseif. который также подвержен ошибкам, например, смешиванию if-else; если еще; в нем есть другие побочные эффекты. с переключателем вы сразу видите n-fork, а с непрерывным if-else-if-else он может быть несколько скрыт. - person aiodintsov; 26.11.2012
comment
Упоминание здесь справочной таблицы зависит от входных данных; для строкового переключателя: конечно, это будет хеш-список; но для большинства переключателей на основе целых чисел (особенно для смежных кандидатов) это будет прямой IL switch - person Marc Gravell; 19.03.2015
comment
@MarcGravell: Да, и инструкция IL switch - это таблица поиска. - person Guffa; 06.06.2015
comment
@Guffa Но разве не будет непрерывного if / else if / else if / else просто проверить одно значение? - person Liggliluff; 31.12.2016
comment
Если разница в производительности незначительна, я всегда буду использовать оператор switch(). Вы когда-нибудь пробовали отлаживать массивное if() дерево операторов в Visual Studio? Вы сожжете свою кнопку F10, пытаясь выяснить, какой оператор if() соответствует; оператор switch() немедленно переведет вас к соответствующему случаю. - person Mass Dot Net; 22.03.2017
comment
Что такое хеш-список? Меня интересует, как компилятор может генерировать хэш из переменной управления переключением в область реализованных случаев без конфликтов и эффективно. - person MikeB; 28.11.2020
comment
Кто-нибудь знает, что происходит в java? Это то же самое, что и C #? - person CodeSlave; 07.06.2021

Почему тебя это беспокоит?

В 99,99% случаев вам все равно.

Маловероятно, что такого рода микрооптимизации повлияют на производительность вашего кода.

Кроме того, если вам НЕОБХОДИМО проявить заботу, вам следует выполнить профилирование производительности вашего кода. В этом случае определение разницы в производительности между случаем переключения и блоком if-else будет тривиальным.

Изменить: для ясности: реализуйте тот дизайн, который более понятен и удобнее в обслуживании. Обычно, когда вы сталкиваетесь с огромным блоком switch-case или if-else, решение состоит в использовании полиморфизма. Найдите изменяющееся поведение и инкапсулируйте его. Раньше мне приходилось иметь дело с огромным и уродливым кодом для переключателей, подобным этому, и, как правило, его не так уж и сложно упростить. Но так приятно.

person Wedge    schedule 20.04.2009
comment
Абсолютно не согласен. Вы определенно должны всегда заботиться о нем не столько из-за производительности, сколько из-за того, что это также влияет на читаемость кода и ремонтопригодность. И, как упоминалось другими, вы могли бы подумать о лучшем использовании полиморфизма. - person Dirk Vollmar; 20.04.2009
comment
О, я согласен с тем, что вы всегда должны заботиться о удобочитаемости и ремонтопригодности. Правильный способ переписать огромный блок switch / case - это, вероятно, полиморфизм (который, кстати, вероятно, немного медленнее, но вам все равно). Макрооптимизация (хороший дизайн) всегда лучше микрооптимизации (более быстрые операторы). - person Wedge; 20.04.2009
comment
Согласен - если вам нужно заботиться об этом уровне оптимизации, вам, вероятно, в первую очередь не следует использовать управляемый язык на основе CLR. - person GrahamS; 27.04.2009
comment
@GrahamS, это немного неверно. виртуальные машины могут быть почти такими же быстрыми, как и настоящие ... не в последнюю очередь потому, что среда выполнения может оптимизировать намного лучше, чем компилятор, потому что она может измерять то, что на самом деле нуждается в оптимизации. PS: Мое решение Java для Лабиринта Болтона занимает 0,03375655565 секунды. Для опубликованного победившего решения C # требуется 0,166 секунды, а на втором месте C ++ - 429,46 секунды, чтобы найти неправильный ответ. И CLR по своей сути медленный? Хммм ... Не думаю, Тим ;-) - person corlettk; 18.05.2009
comment
Тип мышления Вам никогда не нужно беспокоиться, потому что производительность никогда не является проблемой. Как вообще программист может это учитывать? как программист, вам нужно знать, что происходит под капотом, знать компилятор и использовать большую часть его, потому что однажды эти дополнительные MS могут спасти вам день. Исходя из C ++, я вижу много такого мышления и поведения в C #, и это позор. Скорее ответьте на его вопрос, чем не обращайте на него внимания. - person Tordin; 08.03.2017
comment
Рассмотрим более общий случай, когда вы пишете функцию, которая будет вызываться ›100 тысяч раз. Я обычно называю эти множители. Например, оператор if в цикле for в рекурсивной функции имеет 2 множителя как из цикла, так и из функции. Небольшое улучшение основной части оператора if может обеспечить ОГРОМНЫЙ прирост производительности. Подобное мышление при проектировании может помочь предотвратить проблемы в будущем, из-за которых вам придется использовать инструмент профилирования. Это законный вопрос, и его нельзя игнорировать. - person wizard07KSU; 14.06.2017
comment
@ wizard07KSU 100к? 100 тыс. Сравнений if / else в C # могут дать вам одну миллисекунду времени выполнения, только часть которой состоит из сравнений if / else. Как я уже сказал, если у вас есть критически важный для производительности код, то попытка угадать, какой метод оптимизации будет лучшим, неверна, вам необходимо профилировать свой код. Не пытайтесь сократить наносекунды на блок кода, если в этом нет необходимости. - person Wedge; 15.06.2017
comment
Ужасный ответ. - person wild_nothing; 21.06.2017
comment
Почему OP заботится, не имеет значения. Не имеет значения и этот ответ, поскольку он вообще не отвечает на вопрос. Странно, как у этого есть сотни положительных голосов, и все же SO всегда подчеркивал, что нужно оставаться в теме и отвечать на вопросы. - person Amir Asyraf; 05.11.2020

Учитывая эту оценку производительности, корпус коммутатора работает быстрее.

Это вывод:

Результаты показывают, что оператор switch выполняется быстрее, чем лестничная диаграмма if-else-if. Это связано с тем, что компилятор может оптимизировать оператор switch. В случае лестничной диаграммы if-else-if код должен обрабатывать каждый оператор if в порядке, определенном программистом. Однако, поскольку каждый случай в операторе switch не полагается на более ранние варианты, компилятор может изменить порядок тестирования таким образом, чтобы обеспечить максимально быстрое выполнение.

person Michael Klement    schedule 20.04.2009

Еще одна вещь, которую следует учитывать: действительно ли это узкое место вашего приложения? Крайне редки случаи, когда такая оптимизация действительно требуется. В большинстве случаев вы можете добиться большего ускорения, переосмыслив свои алгоритмы и структуры данных.

person Vilx-    schedule 20.04.2009

Я бы сказал, что переход - это лучший способ, это и быстрее, и лучше для практики.

Существуют различные ссылки, такие как (http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx), которые показывают сравнительные тесты, сравнивающие эти два.

person Shaun Bohannon    schedule 20.04.2009

Switch обычно выполняется быстрее, чем длинный список if, потому что компилятор может генерировать таблицу переходов. Чем длиннее список, тем лучше оператор switch над серией операторов if.

person Steven    schedule 20.04.2009
comment
Обратите внимание, что таблица переходов применяется только (IIRC) для смежных значений. Компилятор нередко генерирует смесь таблиц перехода и breq для сложных несмежных параметров. - person Marc Gravell; 20.04.2009

Не должно быть сложно протестировать, создайте функцию, которая переключает или ifelse между 5 числами, вставляет rand (1,5) в эту функцию и выполняет цикл несколько раз, синхронизируя ее.

person Ólafur Waage    schedule 20.04.2009

Технически они дают точно такой же результат, поэтому их можно оптимизировать примерно так же. Однако существует больше шансов, что компилятор оптимизирует случай переключения с помощью таблицы переходов, чем если.

Я говорю об общем случае. Для 5 записей среднее количество тестов, выполняемых для if, должно быть меньше 2,5, при условии, что вы упорядочиваете условия по частоте. Вряд ли это узкое место, о котором стоит писать домой, если только не в очень тесной петле.

person jfclavette    schedule 20.04.2009

switch обычно переводится компилятором в таблицу поиска, если это возможно. Таким образом, поиск произвольного случая - O (1), вместо того, чтобы на самом деле выполнять несколько сравнений регистра, прежде чем найти тот, который вам нужен.

Поэтому во многих случаях цепочка _2 _ / _ 3_ будет медленнее. Однако, в зависимости от частоты, с которой поступают ваши дела, это может не иметь никакого значения.

person Joey    schedule 20.04.2009

Гораздо более важными, чем преимущества в производительности switch (которые относительно невелики, но стоит отметить), являются проблемы с удобочитаемостью.

Я, например, нахожу оператор switch чрезвычайно ясным в смысле намерений и чистых пробелов по сравнению с цепочками if.

person annakata    schedule 20.04.2009

Я не уверен, но я считаю, что скорость одного или другого меняется в зависимости от языка программирования, который вы используете.

Я обычно предпочитаю использовать переключатель. Таким образом код будет проще читать.

person user308693    schedule 04.04.2010

Краткий ответ: оператор Switch работает быстрее

Оператор if вам понадобится в среднем два сравнения (при запуске вашего примера кода), чтобы перейти к правильному предложению.

В операторе switch среднее количество сравнений будет равно одному независимо от того, сколько у вас разных случаев. Компилятор / виртуальная машина создаст «поисковую таблицу» возможных параметров во время компиляции.

Могут ли виртуальные машины оптимизировать оператор if аналогичным образом, если вы часто запускаете этот код?

person AnnaR    schedule 20.04.2009

Поскольку оператор switch выражает то же намерение, что и ваша цепочка if / else, но более ограниченным формальным образом, ваше первое предположение должно заключаться в том, что компилятор сможет оптимизировать его лучше, поскольку он может сделать больше выводов об условиях, наложенных на ваш код (т.е. только одно состояние может быть истинным, сравниваемое значение является примитивным типом и т. д.) Это довольно безопасная общая истина, когда вы сравниваете две похожие языковые структуры на производительность во время выполнения.

person mqp    schedule 20.04.2009

см. http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.switch%28VS.71%29.aspx

Оператор switch в основном представляет собой таблицу поиска, у нее есть известные параметры, а оператор if похож на логический тип. по мне, switch и if-else такие же, но для логического переключателя может помочь лучше. в то время как if-else также помогает разобраться в чтении.

person User42590    schedule 29.09.2012