Есть ли влияние на производительность при вызове ToList ()?



при использовании ToList() есть ли влияние на производительность, которая должна быть рассмотрена?



Я пишу запрос для извлечения файлов из каталога, который представляет запрос:



string[] imageArray = Directory.GetFiles(directory);



однако, так как мне нравится работать с List<> вместо этого, я решил поставить на...



List<string> imageList = Directory.GetFiles(directory).ToList();



Итак, есть ли какое-то влияние на производительность, которое следует учитывать при принятии решения о таком преобразовании - или только учитывать, когда дело с большим количеством файлов? Это незначительное преобразование?

901   8  

8 ответов:

IEnumerable.ToList()

да IEnumerable<T>.ToList() имеет влияние на производительность, это O (n) операция, хотя она, вероятно, потребует внимания только в критических операциях производительности.

The ToList() операция будет использовать List(IEnumerable<T> collection) конструктор. Этот конструктор должен сделать копию массива (в более общем случае IEnumerable<T>), иначе будущие модификации исходного массива изменятся на исходном T[] также не хотелось бы вообще.

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

полезный совет, As vs To

Вы заметите, что в 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> есть два случая:

  1. исходная коллекция реализует ICollection<T>: потом ICollection<T>.Count is используется для получения точного размера исходной коллекции и соответствующий резервный массив выделяется перед копированием всех элементов исходной коллекции в резервный массив с помощью ICollection<T>.CopyTo(). Эта операция довольно эффективна и, вероятно, будет сопоставляться с некоторой инструкцией процессора для копирования блоков памяти. Однако с точки зрения производительности память требуется для нового массива, а циклы процессора необходимы для копирования всех элементов.

  2. в противном случае размер исходного коллекция неизвестна и перечислитель 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>, вы материализовать the IEnumerable<T> (обычно запрос).

Comments

    Ничего не найдено.