Ответ 1
Ниже приведен краткий обзор алгоритмов сортировки, используемых в версиях .NET. Полезно помнить, что List<T>.Sort()
внутренне использует Array<T>.Sort()
- В .NET 2.0-4.0 для сортировки
Array
используется быстрый алгоритм сортировки. Были внесены незначительные изменения в код, но по большей части код остается тем же. - В .NET 4.5 алгоритм сортировки массивов изменился с быстрой сортировки на интроспективный. Это большее изменение, чем раньше, это, по крайней мере, в моих тестах, показывает значительные улучшения в производительности.
Изменен ли алгоритм сортировки в VS2010?
Да, но изменения были незначительными и не влияют на производительность. Рассмотрим сорт против 20 миллионов перетасованных целых чисел 1:
List<int>.Sort() (20 million) .NET 3.5 .NET 4.0 .NET 4.5 --------- --------- --------- 2.564s 2.565s 2.337s
Там нет изменений между версиями v3.5 и v4.0 с точки зрения производительности. Заметное увеличение скорости для v4.5. Ясно, что это не настоящий алгоритм сортировки, который делает разницу.
Прежде чем перейти к следующему вопросу, позвольте мне поделиться результатами моего фактического кода на моей машине:
List<string>.Sort() (1.6 million) .NET 3.5 .NET 4.0 .NET 4.5 --------- --------- --------- 7.953s 11.267s 10.092s
Я получаю похожие результаты, как и вы. Эти результаты являются хорошим ответом на ваш следующий вопрос:
Есть ли что-то другое в базовом CLR, что ухудшает производительность?
Без сомнения. Итак, в чем разница? Разница заключается в реализации сравнения строк. На каждом шаге алгоритма сортировки необходимо сравнить две строки, и это происходит по-разному между версиями v2.0 и v4.0. (См. Дополнительные примечания ниже)
Самый простой способ доказать это - заставить сортировку по порядковой позиции вместо культурной зависимости. Замените lines.Sort();
на lines.Sort(StringComparer.Ordinal);
. Вот что я измерил:
List<string>.Sort(StringComparer.Ordinal) (1.6 million) .NET 3.5 .NET 4.0 .NET 4.5 --------- --------- --------- 4.088s 3.76s 3.454s
Теперь это выглядит лучше! Это более или менее то, что я ожидал; постоянное увеличение скорости для каждой версии выпущенной структуры. MSDN предлагает, что если вы когда-либо проводите нелингвистическое сравнение строки, вы должны использовать порядковое сравнение.
Однако это решает проблему только в том случае, если сравнение или сортировка не чувствительны к культуре. Если вам нужна сортировка, чувствительная к культуре, похоже, вы не сможете избавиться от более медленного времени выполнения, если вы не захотите вернуться к платформе .NET 3.5.
Дополнительные примечания
Если вы не передадите сравнение с List<T>.Sort()
или Array.Sort
, он будет использовать сопоставитель по умолчанию. Сопоставления по умолчанию для строк .NET использует сопоставитель из текущей текущей культуры. Оттуда он вызывает некоторые внутренние функции в собственных библиотеках среды выполнения .NET.
В версии 2.0-3.5 он вызывает COMNlsInfo::Compare
и COMNlsInfo::CompareFast
. Здесь выглядит стек вызовов (kinda):
String.CompareTo(string) +--System.Globalization.CompareInfo.Compare(string,string,CompareOptions) +--mscorwks.dll!COMNlsInfo::Compare +--mscorwks.dll!COMNlsInfo::CompareFast
Подобный источник для этих функций виден в реализации общего источника CLI (SSCLI). Он расположен в sscli\clr\src\classlibnative\nls\comnlsinfo.cpp
на строках 1034 и 893 соответственно.
Однако в версии 4.0 это дерево вызовов значительно изменилось:
String.CompareTo(string) +--System.Globalization.CompareInfo.Compare(string,string,CompareOptions) +--clr.dll!COMNlsInfo::InternalCompareString +--clr.dll!SortVersioning::SortDllCompareString +--nlssorting.dll!_SortCompareString +--nlssorting.dll!_AsciiCompareString
Хотел бы я рассказать вам, почему он медленнее, чем другой, но у меня нет никакой подсказки, и нет сравнения с SSCLI для .NET 4.0. Основные изменения в обработке строк в .NET 4.0 не были без проблем. Были проблемы с производительностью связанные со строками в .NET 4.0, однако они действительно не применяются здесь.
1 Все тесты выполнялись на виртуальной машине. Win 2008R2 x64 w/4GB RAM и виртуальный четырехъядерный процессор. Хост-компьютер - это Win7 x64 w/24GB RAM и четырехъядерный процессор Xeon W3540 (2.93ghz) (8 логических процессоров). Результаты в среднем составляют 5 прогонов с удалением лучших и худших времен.