Скажем, у вас должен быть список / массив целых чисел, которые вы должны часто повторять, и я имею в виду очень часто. Причины могут быть разными, но говорят, что это сердце самого внутреннего цикла обработки большого объема.
В целом, можно использовать списки (List) из-за их гибкости в размере. Кроме того, документация msdn утверждает, что списки используют массив внутри и должны работать так же быстро (быстрый просмотр с помощью Reflector подтверждает это). Тем не менее, есть некоторые накладные расходы.
Кто-нибудь на самом деле измерял это? будет ли повторение 6M раз по списку занимать то же время, что и массив?
T[]
противList<T>
может иметь большое значение производительности. Я только что оптимизировал чрезвычайно интенсивное (вложенное) циклическое приложение для перехода от списков к массивам в .NET 4.0. Я ожидал улучшения на 5-10%, но ускорился более чем на 40%! Никаких других изменений, кроме перехода непосредственно из списка в массив. Все перечисления были сделаны сforeach
заявлениями. На основании ответа Marc Gravell, это выглядит какforeach
сList<T>
особенно плохо.Ответы:
Очень легко измерить ...
В небольшом количестве кода обработки с жестким циклом, где я знаю, что длина фиксирована, я использую массивы для этой крошечной микроптимизации; Массивы могут быть немного быстрее, если вы используете индексатор / для формы - но IIRC полагает, что это зависит от типа данных в массиве. Но если вам не нужна микрооптимизация, сделайте ее простой, используйте
List<T>
и т. Д.Конечно, это применимо, только если вы читаете все данные; словарь будет быстрее для поиска на основе ключей.
Вот мои результаты с использованием «int» (второе число - контрольная сумма, чтобы убедиться, что они все сделали одну и ту же работу):
(отредактировано, чтобы исправить ошибку)
на основе испытательного стенда:
источник
Резюме:
Массив нужно использовать:
Список нужно использовать:
LinkedList нужно использовать:
При необходимости добавить ячейки в начале / середине / конце списка (часто)
При необходимости только последовательный доступ (вперед / назад)
Если вам нужно сохранить БОЛЬШИЕ предметы, но количество предметов мало.
Лучше не использовать для большого количества элементов, так как он использует дополнительную память для ссылок.
Больше деталей:
Намного больше деталей:
https://stackoverflow.com/a/29263914/4423545
источник
Я думаю, что производительность будет довольно похожа. Служебная нагрузка, которая возникает при использовании List vs Array, - IMHO, когда вы добавляете элементы в список, и когда список должен увеличивать размер используемого им массива, когда достигается емкость массива.
Предположим, у вас есть список с вместимостью 10, тогда список увеличит его емкость, как только вы захотите добавить 11-й элемент. Вы можете уменьшить влияние на производительность, инициализируя Емкость списка для количества элементов, которые он будет содержать.
Но чтобы выяснить, выполняется ли итерация по списку так же быстро, как итерация по массиву, почему бы вам не провести сравнительный анализ?
В моей системе; перебор массива занял 33 мсек; перебор списка занял 66 мсек.
Честно говоря, я не ожидал, что вариация будет такой большой. Итак, я поместил свою итерацию в цикл: теперь я выполняю обе итерации 1000 раз. Результаты:
Теперь, вариация уже не так велика, но все же ...
Поэтому я запустил .NET Reflector, и получатель индексатора класса List выглядит следующим образом:
Как вы можете видеть, когда вы используете индексатор List, List выполняет проверку, не выходите ли вы за пределы внутреннего массива. Эта дополнительная проверка поставляется с оплатой.
источник
если вы просто получаете одно значение из любого (не в цикле), тогда оба выполняют проверку границ (вы помните, что вы в управляемом коде), просто список делает это дважды. См. Примечания позже, почему это, вероятно, не имеет большого значения.
Если вы используете свой собственный для (int int i = 0; i <x. [Length / Count]; i ++), то ключевое отличие будет следующим:
Если вы используете foreach, то ключевое отличие заключается в следующем:
Проверка границ часто не имеет большого значения (особенно если вы работаете на процессоре с глубоким прогнозированием конвейера и ветвлений - нормой для большинства в наши дни), но только ваше собственное профилирование может сказать вам, если это проблема. Если вы находитесь в частях своего кода, где избегаете выделения кучи (хорошими примерами являются библиотеки или реализации хэш-кода), то гарантируя, что переменная типизирована как List not IList, позволит избежать этой ловушки. Как всегда профиль, если это имеет значение.
источник
[ Смотрите также этот вопрос ]
Я изменил ответ Марка, чтобы использовать реальные случайные числа и фактически делать ту же работу во всех случаях.
Полученные результаты:
Составлено как релиз под VS 2008 SP1. Работает без отладки на Q6600 @ 2,40 ГГц, .NET 3.5 SP1.
Код:
источник
Измерения хороши, но вы получите значительно разные результаты в зависимости от того, что именно вы делаете в своем внутреннем цикле. Измерьте вашу собственную ситуацию. Если вы используете многопоточность, это само по себе нетривиальное занятие.
источник
Действительно, если вы выполняете некоторые сложные вычисления внутри цикла, то производительность индексатора массива по сравнению с индексатором списка может быть настолько незначительно, что в конечном итоге это не имеет значения.
источник
Вот тот, который использует словари, IEnumerable:
источник
Не пытайтесь увеличить емкость, увеличив количество элементов.
Производительность
источник
Я беспокоился о том, что тесты, опубликованные в других ответах, все равно оставят возможность компилятору оптимизировать, устранить или объединить циклы, поэтому я написал такой, который:
В результате производительность прямого массива примерно на 250% выше, чем доступа к массиву, заключенному в IList:
Вот код:
источник
Поскольку List <> использует массивы внутри, базовая производительность должна быть одинаковой. Две причины, почему список может быть немного медленнее:
Чтобы проверить, имеет ли это какое-то значение для вас, вероятно, лучше отрегулировать опубликованные функции синхронизации в соответствии со списком размера, который вы планируете использовать, и посмотреть, каковы результаты для вашего особого случая.
источник
Поскольку у меня был похожий вопрос, это заставило меня быстро начать.
Мой вопрос немного более конкретен: «Какой самый быстрый метод для реализации рефлексивного массива»
Тестирование, проведенное Марком Гравеллом, показывает многое, но не совсем точно по времени доступа. Его время включает в себя зацикливание массива и списков, а также. Так как я также придумал третий метод, который я хотел протестировать, «Словарь», просто для сравнения я расширил код теста для истории.
Во-первых, я делаю тест с использованием константы, которая дает мне определенное время, включая цикл. Это «голое» время, исключающее фактический доступ. Затем я делаю тест с доступом к предметной структуре, это дает мне время, циклы и фактический доступ.
Разница между «голым» временем и временем, включенным в накладные расходы, дает мне представление о времени доступа к структуре.
Но насколько точно это время? Во время теста окна сделают некоторое время нарезки для shure. У меня нет информации о срезах времени, но я полагаю, что они равномерно распределены во время теста и порядка десятков мс, что означает, что точность синхронизации должна быть порядка +/- 100 мс или около того. Немного грубая оценка? В любом случае источник систематической ошибки.
Кроме того, тесты проводились в режиме «Отладка» без оптимизации. В противном случае компилятор может изменить реальный тестовый код.
Итак, я получаю два результата: один для константы, помеченный «(c)», а другой для доступа, помеченный «(n)», а разница «dt» говорит мне, сколько времени занимает фактический доступ.
И вот результаты:
С лучшими оценками ошибок синхронизации (как устранить систематическую ошибку измерения из-за временного среза?) Можно было бы сказать больше о результатах.
Похоже, что List / foreach имеет самый быстрый доступ, но накладные расходы убивают его.
Разница между List / for и List / foreach является странной. Может быть, это связано с обналичиванием денег?
Кроме того, для доступа к массиву не имеет значения, используете ли вы
for
цикл илиforeach
цикл. Результаты расчета времени и его точность делают результаты «сопоставимыми».Использование словаря является самым медленным, я рассмотрел его только потому, что с левой стороны (индексатор) у меня есть разреженный список целых чисел, а не диапазон, который используется в этих тестах.
Вот модифицированный тестовый код.
источник
В некоторых кратких тестах я обнаружил, что комбинация двух из них лучше в том, что я бы назвал достаточно интенсивной математикой:
Тип:
List<double[]>
Тип:
List<List<double>>
Тип:
double[rows * columns]
Выполнение кода:
Мне бы очень хотелось, чтобы у нас были классные матричные классы с аппаратным ускорением, такие как .NET Team с
System.Numerics.Vectors
классом!C # может быть лучшим языком ML с немного большим количеством работы в этой области!
источник