Есть ли влияние на производительность при вызове ToList ()?
при использовании ToList() есть ли влияние на производительность, которая должна быть рассмотрена?
Я пишу запрос для извлечения файлов из каталога, который представляет запрос:
string[] imageArray = Directory.GetFiles(directory);
однако, так как мне нравится работать с List<> вместо этого, я решил поставить на...
List<string> imageList = Directory.GetFiles(directory).ToList();
Итак, есть ли какое-то влияние на производительность, которое следует учитывать при принятии решения о таком преобразовании - или только учитывать, когда дело с большим количеством файлов? Это незначительное преобразование?
8 ответов:
IEnumerable.ToList()да
IEnumerable<T>.ToList()имеет влияние на производительность, это O (n) операция, хотя она, вероятно, потребует внимания только в критических операциях производительности.The
ToList()операция будет использоватьList(IEnumerable<T> collection)конструктор. Этот конструктор должен сделать копию массива (в более общем случаеIEnumerable<T>), иначе будущие модификации исходного массива изменятся на исходномT[]также не хотелось бы вообще.я хотел бы повторить, что это будет иметь значение только с огромным списком, копирование кусков памяти является довольно быстрой операцией для выполнения.
полезный совет,
AsvsToВы заметите, что в LINQ есть несколько методов, которые начинаются с
As(например,AsEnumerable()) иTo(например,ToList()). Методы, которые начинаются сToтребуется преобразование, как указано выше (т. е. может повлиять на производительность), и методы, которые начинаются сAsне нужно и просто потребует некоторого броска или простой операции.дополнительные детали
List<T>вот немного подробнее о том, как
List<T>строительство в случае, если вы заинтересованы :)A
List<T>также использует конструкцию под названием динамический массив, который должен быть изменен по требованию, это событие изменения размера копирует содержимое старого массива в новый массив. Так что все начинается с малого и при необходимости увеличивается в размере.вот в чем разница между
CapacityиCountатрибутыList<T>.Capacityотносится к размеру массива за кулисами,Count- количество элементов вList<T>который всегда<= Capacity. Поэтому, когда элемент добавляется в список, увеличивая его мимоCapacity, размерList<T>удваивается и массив копируется.
есть ли влияние на производительность при вызове toList ()?
Да конечно. Теоретически даже
i++имеет влияние на производительность, это замедляет программу, возможно, на несколько тиков.что значит
.ToListделать?при вызове
.ToList, код вызываетEnumerable.ToList()который является методом расширения, чтоreturn new List<TSource>(source). В соответствующем конструкторе, при худших обстоятельствах, он проходит через элемент контейнер и добавить их по одному в новый контейнер. Поэтому его поведение мало влияет на производительность. Невозможно быть горлышком бутылки производительности вашего приложения.что не так с кодом в вопросе
Directory.GetFilesпроходит через папку и возвращает имена всех файлов тут в память, оно имеет потенциальный риск того, что строка[] стоит много памяти, замедляя все.что должно быть сделано тогда
это зависит. Если вы(а также ваша бизнес-логика) гарантируете, что объем файла в папке всегда мал, код приемлем. Но все равно предлагается использовать ленивую версию:
Directory.EnumerateFilesв C#4. Это гораздо больше похоже на запрос, который не будет выполнен сразу, вы можете добавить больше запросов на него, например:Directory.EnumerateFiles(myPath).Any(s => s.Contains("myfile")), который поиск путь, как только будет найден файл, имя которого содержит "myfile". Это, очевидно, имеет лучшую производительность, чем
.GetFiles.
есть ли влияние на производительность при вызове toList ()?
Да есть. Используя метод расширения
пониманиеEnumerable.ToList()построит новыйList<T>объектIEnumerable<T>исходная коллекция, которая, конечно же, влияет на производительность.List<T>может помочь вам определить, если производительность является значительным.
List<T>использует массив (T[]) для хранения элементов списка. Массивы не могут быть расширяется, как только они выделяются такList<T>будет использовать массив большого размера для хранения элементов списка. КогдаList<T>выходит за пределы размера базового массива новый массив должен быть выделен и содержимое старого массива должен быть скопирован в новый больший массив, прежде чем список может расти.если новый
List<T>состоит изIEnumerable<T>есть два случая:
исходная коллекция реализует
ICollection<T>: потомICollection<T>.Countis используется для получения точного размера исходной коллекции и соответствующий резервный массив выделяется перед копированием всех элементов исходной коллекции в резервный массив с помощьюICollection<T>.CopyTo(). Эта операция довольно эффективна и, вероятно, будет сопоставляться с некоторой инструкцией процессора для копирования блоков памяти. Однако с точки зрения производительности память требуется для нового массива, а циклы процессора необходимы для копирования всех элементов.в противном случае размер исходного коллекция неизвестна и перечислитель
IEnumerable<T>используется для добавления каждого исходного элемента по одному в новыйList<T>. Изначально резервный массив пуст и создается массив размером 4. Затем, когда этот массив слишком мал, размер удваивается, поэтому резервный массив растет так: 4, 8, 16, 32 и т. д. Каждый раз, когда Резервный массив растет, он должен быть перераспределен, и все элементы, сохраненные до сих пор, должны быть скопированы. Эта операция является намного более дорогостоящей по сравнению с первым случаем, когда массив правильный размер может быть создан сразу.кроме того, если ваша исходная коллекция содержит, скажем, 33 элемента, список в конечном итоге будет использовать массив из 64 элементов, тратящих некоторую память.
в вашем случае исходная коллекция представляет собой массив, который реализует
ICollection<T>таким образом, влияние на производительность-это не то, о чем вы должны беспокоиться, если ваш исходный массив не очень большой. ЗвонюToList()будет просто скопировать исходный массив и обернуть его в
есть ли влияние на производительность, которое необходимо учитывать?"
проблема с вашим точным сценарием заключается в том, что в первую очередь ваша реальная забота о производительности будет зависеть от скорости жесткого диска и эффективности кэша диска.
С этой точки зрения, воздействие, безусловно, незначительно до такой степени, что нет это не нужно рассматривать.
но только если вам действительно нужны функции
List<>структура, которая, возможно, либо сделает вас более продуктивным, либо ваш алгоритм более дружелюбным, или какое-то другое преимущество. В противном случае вы просто намеренно добавляете незначительный хит производительности, без всякой причины. В этом случае, естественно, вы не должны этого делать! :)
ToList()создает новый список и помещает в него элементы, что означает, что существует связанная с этим стоимостьToList(). В случае небольшой коллекции это будет не очень заметная стоимость, но наличие огромной коллекции может вызвать хит производительности в случае использования ToList.Как правило, вы не должны использовать ToList (), если работа, которую вы делаете, не может быть выполнена без преобразования коллекции в список. Например, если вы просто хотите перебрать коллекцию, которую вам не нужно выполнять Список
Если вы выполняете запрос к источнику данных, например к базе данных, используя LINQ к SQL, то стоимость ведения список гораздо больше, потому что, когда вы используете список с LINQ к SQL вместо того, чтобы делать просрочивший исполнение, т. е. Загружать элементы при необходимости (что может быть полезно во многих сценариях) его моментально загружает элементы из базы данных в память
это будет так же (в)эффективно, как делать:
var list = new List<T>(items);если вы разберете исходный код конструктора, который принимает
IEnumerable<T>, вы увидите, что он будет делать несколько вещей:
вызов
collection.Count, Так что еслиcollection- этоIEnumerable<T>, он не понял. Еслиcollection- это массив, список и т. д. он должен быть!--6-->.если
collectionосуществляетICollection<T>, он сохранит элементы во внутреннем массиве с помощьюICollection<T>.CopyToметод. Это должны бытьO(n), будучиnдлина коллекцию.если
collectionне выполнятьICollection<T>, он будет перебирать элементы коллекции и добавит их во внутренний список.так что, да, он будет потреблять больше памяти, так как он должен создать новый список, и в худшем случае, это будет
O(n), так как он будет перебиратьcollectionсоздать копию каждый элемент.
ToList создаст новый список и скопирует элементы из исходного источника во вновь созданный список, поэтому единственное, что нужно скопировать элементы из исходного источника и зависит от размера источника
учитывая производительность извлечения списка файлов,
ToList()ничтожна. Но не совсем для других сценариев. Это действительно зависит от того, где вы используете его.
при вызове массива, списка или другой коллекции вы создаете копию коллекции как
List<T>. Производительность здесь зависит от размера списка. Вы должны делать это, когда это действительно необходимо.в вашем примере, вы вызываете его на массив. Он перебирает массив и добавляет элементы по одному во вновь созданный список. Так что влияние на производительность зависит от количества файлов.
при вызове на
IEnumerable<T>, вы материализовать theIEnumerable<T>(обычно запрос).
Comments