Важно не путать оператор переключения C # с инструкцией переключения CIL.
Переключатель CIL - это таблица переходов, для которой требуется индекс в наборе адресов перехода.
Это полезно только в том случае, если случаи переключателя C # находятся рядом:
case 3: blah; break;
case 4: blah; break;
case 5: blah; break;
Но бесполезно, если их нет:
case 10: blah; break;
case 200: blah; break;
case 3000: blah; break;
(Вам понадобится таблица размером ~ 3000 записей, всего с 3 используемыми ячейками)
С несмежными выражениями компилятор может начать выполнять линейные проверки if-else-if-else.
С большими несмежными наборами выражений компилятор может начать с поиска по двоичному дереву и, наконец, с нескольких последних элементов if-else-if-else.
С наборами выражений, содержащими группы соседних элементов, компилятор может выполнять поиск по двоичному дереву и, наконец, переключать CIL.
Это полно "майя" и "майя", и это зависит от компилятора (может отличаться от Mono или Rotor).
Я воспроизвел ваши результаты на своей машине, используя соседние случаи:
общее время выполнения 10-позиционного переключателя, 10000 итераций (мс): 25,1383
приблизительное время на 10-позиционный переключатель (мс): 0,00251383
общее время выполнения 50-позиционного переключателя, 10000 итераций (мс): 26,593
приблизительное время на 50-позиционный переключатель (мс): 0,0026593
общее время выполнения 5000-позиционного переключателя, 10000 итераций (мс): 23,7094
приблизительное время на 5000-позиционный переключатель (мс): 0,00237094
общее время выполнения переключения на 50000 путей, 10000 итераций (мс): 20,0933
приблизительное время на переключение на 50000 направлений (мс): 0,00200933
Затем я также использовал несмежные выражения:
общее время выполнения 10-позиционного переключателя, 10000 итераций (мс): 19,6189
приблизительное время на 10-позиционный переключатель (мс): 0,00196189
общее время выполнения 500-позиционного переключателя, 10000 итераций (мс): 19,1664
приблизительное время на 500-позиционный переключатель (мс): 0,00191664
общее время выполнения 5000-позиционного переключателя, 10000 итераций (мс): 19,5871
приблизительное время на 5000-позиционный переключатель (мс): 0,00195871
Несмежный оператор переключения регистра 50 000 не будет компилироваться.
"Выражение слишком длинное или сложное для компиляции рядом с 'ConsoleApplication1.Program.Main (string [])'
Что забавно, так это то, что поиск в двоичном дереве выглядит немного (вероятно, не статистически) быстрее, чем инструкция переключения CIL.
Брайан, вы использовали слово « константа », которое имеет очень определенное значение с точки зрения теории сложности вычислений. В то время как упрощенный пример смежных целых чисел может создавать CIL, который считается O (1) (константа), разреженный пример - O (log n) (логарифмический), кластерные примеры лежат где-то посередине, а небольшие примеры - O (n) (линейный ).
Это даже не касается ситуации String, в которой Generic.Dictionary<string,int32>
может быть создана статика , и при первом использовании будут возникать определенные накладные расходы. Производительность здесь будет зависеть от производительности Generic.Dictionary
.
Если вы проверите спецификацию языка C # (а не спецификацию CIL), вы обнаружите, что «15.7.2 Оператор переключения» не упоминает «постоянное время» или что базовая реализация даже использует инструкцию переключения CIL (будьте очень осторожны, предполагая такие вещи).
В конце концов, переключение C # на целочисленное выражение в современной системе - это субмикросекундная операция, о которой обычно не стоит беспокоиться.
Конечно, это время будет зависеть от машин и условий. Я бы не стал обращать внимание на эти временные тесты, микросекунды, о которых мы говорим, затмеваются любым выполняемым «реальным» кодом (и вы должны включить какой-то «настоящий код», иначе компилятор оптимизирует ветвление), или джиттер в системе. Мои ответы основаны на использовании IL DASM для изучения CIL, созданного компилятором C #. Конечно, это не окончательный вариант, поскольку фактические инструкции, выполняемые ЦП, затем создаются JIT.
Я проверил последние инструкции процессора, фактически выполняемые на моем компьютере x86, и могу подтвердить, что простой смежный переключатель набора делает что-то вроде:
jmp ds:300025F0[eax*4]
Если поиск по бинарному дереву заполнен:
cmp ebx, 79Eh
jg 3000352B
cmp ebx, 654h
jg 300032BB
…
cmp ebx, 0F82h
jz 30005EEE