LINQ performance FAQ
Я пытаюсь разобраться с LINQ. Больше всего меня беспокоит то, что даже когда я лучше понимаю синтаксис, я не хочу невольно жертвовать производительностью для выразительности.
являются ли они хорошими централизованными хранилищами информации или книг для "эффективного LINQ"? В противном случае, какова ваша личная любимая высокопроизводительная техника LINQ ?
меня в первую очередь интересует LINQ to Objects, но все предложения по LINQ to SQL и LINQ to XML также приветствуется, конечно. Спасибо.
5 ответов:
простое понимание того, что LINQ делает внутри, должно дать достаточно информации, чтобы знать, принимаете ли вы удар по производительности.
вот простой пример, где LINQ помогает производительности. Рассмотрим этот типичный олдскульный подход:
List<Foo> foos = GetSomeFoos(); List<Foo> filteredFoos = new List<Foo>(); foreach(Foo foo in foos) { if(foo.SomeProperty == "somevalue") { filteredFoos.Add(foo); } } myRepeater.DataSource = filteredFoos; myRepeater.DataBind();таким образом, приведенный выше код будет повторяться дважды и выделять второй контейнер для хранения отфильтрованных значений. Какая потеря! Сравните с:
var foos = GetSomeFoos(); var filteredFoos = foos.Where(foo => foo.SomeProperty == "somevalue"); myRepeater.DataSource = filteredFoos; myRepeater.DataBind();это только повторяется один раз (когда ретранслятор связан); это только когда-либо использует оригинальный контейнер;
filteredFoosэто просто промежуточный перечислителя. И если по какой-то причине вы решите не привязывать ретранслятор позже, ничего не пропадет даром. Вы даже не повторяете и не оцениваете один раз.когда вы попадаете в очень сложную последовательность манипуляций, вы можете потенциально получите много, используя присущее LINQ использование цепочки и ленивой оценки. Опять же, как и все, это просто вопрос понимания того, что это на самом деле делающий.
LINQ, как встроенная технология, имеет свои преимущества и недостатки. Код, лежащий в основе методов расширения, имеет значительное внимание к производительности, уделяемое ему командой .NET, и его способность обеспечивать ленивую оценку означает, что стоимость выполнения большинства манипуляций с набором объектов распределяется по более крупному алгоритму, требующему манипулируемого набора. Однако есть некоторые вещи, которые вам нужно знать, которые могут сделать или сломать ваш код спектакль.
прежде всего, Linq не волшебным образом экономит ваше время или память, необходимые для выполнения операции; он просто может задержать эти операции до тех пор, пока это абсолютно необходимо. Предложение orderby() выполняет алгоритм быстрой сортировки, которая потребуется время nlogn точно так же, как если бы вы написали свой собственный QuickSorter или использовать список.Сортировка () в нужное время. Поэтому всегда помните о том, что вы просите Linq сделать с серией при написании запросов; если манипуляция не требуется, посмотрите реструктурируйте цепочку запросов или методов, чтобы избежать этого.
точно так же некоторые операции (сортировка, группировка, агрегаты) требуют знания всего набора, на который они действуют. Самый последний элемент в серии может быть первым, который операция должна вернуть из своего итератора. Кроме того, поскольку операции Linq не должны изменять свой исходный перечислимый, но многие из используемых ими алгоритмов будут (т. е. сортировка на месте), эти операции заканчиваются не только оценкой, но и копирование всего перечисляемого в конкретную, конечную структуру, выполнение операции и уступка через нее. Итак, когда вы используете OrderBy() в операторе и просите элемент из конечного результата, все, что может дать ему IEnumerable, оценивается, хранится в памяти в виде массива, сортируется, а затем возвращается по одному элементу за раз. Мораль заключается в том, что любая операция, которая требует конечного набора вместо перечислимого, должна быть помещена как можно позже в запрос, позволяя другим такие операции, как Where() и Select (), уменьшают мощность и объем памяти исходного набора.
наконец, методы Linq значительно увеличивают размер стека вызовов и объем памяти вашей системы. Каждая операция, которая должна знать весь набор, сохраняет весь исходный набор в памяти до тех пор, пока последний элемент не будет повторен, и оценка каждого элемента будет включать стек вызовов по крайней мере в два раза глубже, чем количество методов в вашей цепочке или предложениях в вашем встроенном оператор (вызов MoveNext() каждого итератора или получение GetEnumerator, плюс по крайней мере один вызов каждой лямбды по пути). Это просто приведет к большему, более медленному алгоритму, чем интеллектуальный встроенный алгоритм, который выполняет те же самые манипуляции. Основным преимуществом технологии LINQ заключается в простоте кода. Создание, а затем сортировка, словарь списков групп значений не очень легко понять код (поверьте мне). Микро-оптимизации могут запутать его дальше. Если производительность ваша основная забота, то не используйте Linq; это добавит примерно 10% времени накладных расходов и в несколько раз больше памяти накладных расходов на управление списком на месте самостоятельно. Однако ремонтопригодность обычно является основной заботой разработчиков, и Linq определенно помогает в этом.
на удар производительности: если производительность вашего алгоритма является священным, бескомпромиссным первым приоритетом, вы будете программировать на неуправляемом языке, таком как C++; .NET будет намного медленнее просто в силу это управляемая среда выполнения с собственной компиляцией JIT, управляемой памятью и дополнительными системными потоками. Я бы принял философию того, что это "достаточно хорошо"; Linq может вводить замедления по своей природе, но если вы не можете сказать разницу, и ваш клиент не может сказать разницу, то для всех практических целей нет никакой разницы. "Преждевременная оптимизация-это корень всех зол"; заставить его работать, а затем искать возможности сделать его более производительным, пока вы и ваш клиент согласитесь, это достаточно хорошо. Это всегда может быть" лучше", но если вы не хотите быть ручным машинным кодом, вы найдете точку, короткую от той, в которой вы можете объявить победу и двигаться дальше.
существуют различные факторы, которые влияют на производительность.
часто разработка решения с использованием LINQ будет предлагать довольно разумную производительность, потому что система может построить дерево выражений для представления запроса без фактического выполнения запроса во время его сборки. Только при повторении результатов он использует это дерево выражений для создания и выполнения запроса.
с точки зрения абсолютной эффективности, бег против предопределенных хранимых процедур вы можете смотрите некоторые хиты производительности, но обычно подход заключается в разработке решения с использованием системы, которая предлагает разумную производительность (например, LINQ), и не беспокоиться о нескольких процентах потери производительности. Если запрос выполняется медленно, то, возможно, вы смотрите на оптимизацию.
реальность такова, что большинство запросов не будет иметь ни малейшей проблемы с выполнением через LINQ. Другой факт заключается в том, что если ваш запрос выполняется медленно, это, вероятно, более вероятно, будут проблемы с индексированием, структурой и т. д., чем с самим запросом, поэтому даже при поиске оптимизации вы часто не будете касаться LINQ, а только структуры базы данных, с которой он работает.
для обработки XML, если у вас есть документ, загружаемый и анализируемый в память (например, что-либо на основе модели DOM или XmlDocument или что-то еще), то вы получите больше использования памяти, чем системы, которые делают что-то вроде поднятия событий, чтобы указать на поиск начального или конечного тега, но не строят полная версия документа в памяти (например, SAX или XmlReader). Недостатком является то, что обработка на основе событий, как правило, является более сложной. Опять же, с большинством документов не будет проблем - большинство систем имеют несколько ГБ ОЗУ, поэтому занять несколько МБ, представляющих один XML-документ, не является проблемой (и вы часто обрабатываете большой набор XML-документов, по крайней мере, несколько последовательно). Это только если у вас есть огромный XML-файл, который будет занимать до 100 МБ, что вы беспокоитесь о конкретный выбор.
имейте в виду, что LINQ позволяет вам перебирать списки в памяти и т. д., Поэтому в некоторых ситуациях (например, когда вы собираетесь снова и снова использовать набор результатов в функции) вы можете использовать .ToList или .ToArray, чтобы вернуть результаты. Иногда это может быть полезно, хотя обычно вы хотите попробовать использовать запрос базы данных, а не в памяти.
Что касается личных фаворитов-NHibernate LINQ - это инструмент объектно-реляционного отображения это позволяет вам определять классы, определять детали отображения, а затем получать его для создания базы данных из ваших классов, а не наоборот, и поддержка LINQ довольно хороша (конечно, лучше, чем подобные дозвуковые).
в linq to SQL вам не нужно так много заботиться о производительности. вы можете связать все свои утверждения так, как вы думаете, что это наиболее читабельно. Linq просто переводит все ваши операторы в 1 оператор SQL в конце, который только вызывается/выполняется в конце (например, когда вы вызываете
.ToList()a
varможет содержать этот оператор без его выполнения, если вы хотите применить различные дополнительные операторы в разных условиях. Выполнение в конце концов происходит только тогда, когда вы вы хотите перевести свои утверждения в результат, такой как объект или список объектов.
есть проект codeplex под названием i4o, который я использовал некоторое время назад, который может помочь улучшить производительность Linq для объектов в тех случаях, когда вы делаете сравнения равенства, например
from p in People where p.Age == 21 select p;http://i4o.codeplex.com/ Я не тестировал его с .Net 4, поэтому не могу с уверенностью сказать, что он все равно будет работать, но стоит проверить. Чтобы заставить его работать над своей магией, вам в основном просто нужно украсить свой класс некоторыми атрибутами, чтобы указать, какое свойство должно быть индексировано. когда я однако он использовал его до того, как он работает только с сравнениями равенства.
Comments