Важно не путать оператор переключения 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.
При больших несмежных наборах выражений компилятор может начать поиск в двоичном дереве и, наконец, если-еще-если-еще, последние несколько элементов.
В случае наборов выражений, содержащих скопления смежных элементов, компилятор может выполнять поиск в двоичном дереве и, наконец, переключение CIL.
Он полон "mays" и "mights" и зависит от компилятора (может отличаться в зависимости от 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 оператор switch» не упоминает о «постоянном времени» или о том, что базовая реализация даже использует инструкцию переключения CIL (будьте очень осторожны, предполагая такие вещи).
В конце концов, переключение C # на целочисленное выражение в современной системе - это операция за микросекунду, о которой обычно не стоит беспокоиться.
Конечно, это время будет зависеть от машин и условий. Я бы не стал обращать внимание на эти временные тесты: длительность микросекунды, о которой мы говорим, затмевается любым «реальным» выполняемым кодом (и вы должны включить некоторый «реальный код», иначе компилятор оптимизирует ветку) джиттер в системе. Мои ответы основаны на использовании IL DASM для проверки CIL, созданного компилятором C #. Конечно, это не является окончательным, поскольку фактические инструкции, которые выполняет ЦП, затем создаются JIT.
Я проверил окончательные инструкции процессора, фактически выполненные на моем компьютере с архитектурой x86, и могу подтвердить, что простой смежный переключатель set выполняет что-то вроде:
jmp ds:300025F0[eax*4]
Где поиск в двоичном дереве полон:
cmp ebx, 79Eh
jg 3000352B
cmp ebx, 654h
jg 300032BB
…
cmp ebx, 0F82h
jz 30005EEE