Вопрос

Система, над которой я здесь работаю, была написана до .net 2.0 и не имела преимуществ дженериков.В конечном итоге он был обновлен до версии 2.0, но ни один из кодов не был переработан из-за нехватки времени.Есть несколько мест, где код использует ArraysLists и т.д.которые хранят вещи как объекты.

С точки зрения производительности, насколько важно изменить код на использование дженериков?Я знаю, что с точки зрения производительности, упаковки, распаковки и т.д., Это неэффективно, но какой прирост производительности действительно будет от его изменения?Являются ли дженерики чем-то, что можно использовать на постоянной основе, или это достаточное изменение производительности, чтобы предпринять сознательные усилия по обновлению старого кода?

Это было полезно?

Решение

Технически производительность дженериков, как вы говорите, лучше.Однако, если производительность не является чрезвычайно важной И вы уже оптимизировали работу в других областях, вы, скорее всего, добьетесь ГОРАЗДО больших улучшений, проводя время в другом месте.

Я бы предложил:

  • используйте дженерики в будущем.
  • если у вас есть надежные модульные тесты, то при касании кода выполняйте рефакторинг до дженериков
  • потратьте другое время на рефакторинг / измерение, которые значительно повысят производительность (вызовы базы данных, изменение структур данных и т.д.), А не на несколько миллисекунд здесь и там.

Конечно, есть причины, помимо производительности, для перехода на дженерики:

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

Другие советы

Вот результаты, которые я получил в результате простого синтаксического анализа строки из файла размером 100 КБ 100 000 раз.Общий список (символов) занял 612,293 секунды, чтобы просмотреть файл 100 000 раз.ArrayList потребовалось 2880,415 секунд, чтобы просмотреть файл 100 000 раз.Это означает, что в данном сценарии (как и ваш пробег будет vary) общий список (символов) работает в 4,7 раза быстрее.

Вот код, который я прогнал 100 000 раз:

Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
    Dim genList As New ArrayList

    For Each ch As Char In strToProcess.ToCharArray
        genList.Add(ch)
    Next

    Dim dummy As New System.Text.StringBuilder()
    For i As Integer = 0 To genList.Count - 1
        dummy.Append(genList(i))
    Next

End Sub

 Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
     Dim genList As New List(Of Char)

     For Each ch As Char In strToProcess.ToCharArray
         genList.Add(ch)
     Next

     Dim dummy As New System.Text.StringBuilder()
     For i As Integer = 0 To genList.Count - 1
         dummy.Append(genList(i))
     Next
 End Sub

Единственный способ узнать наверняка - это профилировать ваш код с помощью такого инструмента, как dotTrace.

http://www.jetbrains.com/profiler/

Вполне возможно, что упаковка / распаковка тривиальна в вашем конкретном приложении и не стоила бы рефакторинга.В дальнейшем вам все равно следует рассмотреть возможность использования дженериков из-за безопасности типов во время компиляции.

Дженерики, будь то Java или .NET, следует использовать для проектирования и безопасности типов, а не для повышения производительности.Автобоксинг отличается от дженериков (по существу, неявных преобразований объекта в примитив), и, как вы упомянули, вам НЕ следует использовать их вместо примитива, если требуется много арифметических или других операций, которые приведут к снижению производительности из-за повторного создания / уничтожения неявного объекта.

В целом, я бы предложил использовать going forward и обновлять существующий код только в том случае, если его необходимо очистить в целях безопасности типов / проектирования, а не производительности.

Это зависит от того, лучший ответ - профилировать ваш код и посмотреть.Мне нравится AQTime, но для этого существует несколько пакетов.

В общем, если ArrayList используется ЧАСТО, возможно, стоит переключить его на универсальную версию.Хотя на самом деле, скорее всего, вы даже не смогли бы измерить разницу в производительности.Упаковка и распаковка - это дополнительные шаги, но современные компьютеры настолько быстры, что это практически не имеет значения.Поскольку ArrayList на самом деле является обычным массивом с красивой оболочкой, вы, вероятно, увидите гораздо больший прирост производительности за счет лучшего выбора структуры данных (ArrayList.Remove равен O (n)!), чем при преобразовании в generics.

Редактировать:Программист вне закона прав: вы по-прежнему будете упаковывать и распаковывать файлы с помощью дженериков, просто это происходит неявно.Однако весь код, связанный с проверкой исключений и нулей при приведении и ключевых слов "is / as", немного помог бы.

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

Какое отношение автоупаковка / распаковка имеет к дженерикам?Это всего лишь проблема безопасности типов.При использовании коллекции, не являющейся универсальной, вам необходимо явно привести обратно к фактическому типу объекта.С дженериками вы можете пропустить этот шаг.Я не думаю, что есть разница в производительности в ту или иную сторону.

Моя старая компания действительно рассматривала эту проблему.Подход, который мы избрали, был следующим:если рефакторинг прост, сделайте это;если нет (т.е.это затронет слишком много классов), оставьте это на более позднее время.Это действительно зависит от того, есть ли у вас время на это, или есть ли более важные элементы для кодирования (т.Е.функции, которые вы должны внедрять для клиентов).

С другой стороны, если вы не работаете над чем-то для клиента, продолжайте и потратьте время на рефакторинг.Это улучшит читабельность кода для вас самих.

Зависит от того, сколько всего содержится в вашем коде.Если вы привязываете или отображаете большие списки в пользовательском интерфейсе, вы, вероятно, увидите значительный прирост производительности.

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

Если вы используете много ArrayLists в своем коде, и было бы большой проблемой заменить их (что может повлиять на ваши расписания), тогда вы могли бы принять подход "если вы коснетесь этого, измените это".

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

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

Если объекты в ArrayLists являются типами объектов, вы немного выиграете, если не приведете их к правильному типу.Если это типы значений (структуры или примитивы, такие как Int32), то процесс упаковки / распаковки добавляет много накладных расходов, и общие коллекции должны быть намного быстрее.

Вот статья MSDN на эту тему

Generics обладает намного лучшей производительностью, особенно если вы будете использовать value-type (int, bool, struct и т.д.), Где вы получите заметный прирост производительности.

  1. Использование Arraylist с типами значений вызывает упаковку / распаковку, которая, если выполняется несколько сотен раз, существенно медленнее, чем при использовании универсального списка.

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

Я писал о здесь.

Использование дженериков также должно означать, что ваш код будет более простым в использовании, если вы хотите использовать такие вещи, как linq, в более поздних версиях c #.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top