Как опыт обучения, я недавно попробовал реализовать Quicksort with 3 way partitioning в C#.Ручное внедрение высокопроизводительных алгоритмов в .NET
Помимо необходимости добавить дополнительную проверку диапазона влево/вправо перед рекурсивным вызовом, он работает очень хорошо.
Я знал заранее, что каркас обеспечивает built-in Quicksort implementation в списке <> .Sort (через Array.Sort). Поэтому я попробовал некоторое базовое профилирование для сравнения производительности. Результаты: встроенный метод List List <> .Sort, работающий в тех же списках, выполняет примерно в 10 раз быстрее, чем моя собственная ручная реализация.
Используя отражатель, я обнаружил, что фактическая сортировка в списке <> .Sort реализована во внешнем коде, а не в IL (в функции с именем tryszsort()).
Глядя на мою собственную реализацию Quicksort, я ожидал бы, что замена рекурсивных вызовов на итерацию может дать некоторое улучшение. Кроме того, отключение проверки границ массива (если возможно) также может дать некоторые преимущества. Возможно, это приблизится к встроенной реализации, но я не уверен.
Итак, мой вопрос: реалистично ли ожидать, что производительность в оптимизированном алгоритме (написанная в .NET IL, связанная с собственным кодом) может конкурировать с производительностью алгоритма, реализованного извне?
Еще раз, я понимаю, что Quicksort предоставляется как часть фреймворка, для меня это было всего лишь опытом обучения. Однако есть также много алгоритмов (CRC32 приходит на ум), которые не предоставляются, но все же могут иметь большое значение для многих приложений. Вот связанный с этим вопрос относительно implementing CRC32 in .NET и проблем с производительностью.
Итак, если вам нужно реализовать такой алгоритм в .NET, каковы основные соображения производительности для понимания, чтобы ваш алгоритм мог по крайней мере приблизиться к производительности внешнего кода?
[Update]
Я улучшил скорость выполнения в пределах примерно 10% от встроенного Array.sort путем изменения алгоритма для работы на простом массиве Int вместо List. В Reflector я вижу, что это позволяет избежать операции Callvirt() для каждого get или set в списке. Я думал, что это может улучшить ситуацию, но я удивлен, насколько.
У меня всегда создавалось впечатление, что большинство реализаций быстрой сортировки переключится на сортировку слияния после спуска на заданное количество уровней рекурсии. Не могли бы вы опубликовать свой код, чтобы увидеть улучшения? – Juliet