Объединение заявлений LINQ для эффективности - PullRequest
1 голос
/ 03 февраля 2010

относительно linq к объектам, если я использую .Where (x => x ....), а затем сразу же использую .SkipWhile (x => x ...), это влечет за собой снижение производительности, потому что я дважды пересматривать коллекцию?

Должен ли я найти способ поместить все в предложение Where или в предложение SkipWhile?

Ответы [ 5 ]

7 голосов
/ 03 февраля 2010

Будет небольшая неэффективность из-за объединения итераторов, но на самом деле она будет очень незначительной. (В частности, хотя каждый соответствующий элемент будет виден обоим операторам, они не будут буферизироваться или что-то в этом роде. LINQ to Object не собирается создавать новый список всех подходящих элементов и затем запустить SkipWhile над ним.)

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

2 голосов
/ 03 февраля 2010

Вы не дважды просматриваете коллекцию, когда используете Where и SkipWhile.

. Метод Where направляет свой вывод в метод SkipWhile.по одному элементу за раз, и аналогичным образом метод SkipWhile будет передавать свои выходные данные любому последующему методу по одному элементу за раз.

(будут небольшие издержки, потому что компилятор генерирует отдельные объекты итератора для каждого методаза кулисами. Но если бы я беспокоился о накладных расходах сгенерированных компилятором итераторов, то, вероятно, я бы не стал использовать LINQ.)

2 голосов
/ 03 февраля 2010

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

Большинство операторов LINQ не будут выполнять итерацию по всей коллекции для каждого оператора, они просто обрабатывают один элемент и передаютэто на следующий оператор.Есть исключения из этого, такие как Reverse и OrderBy, но, как правило, если вы используете Where и SkipWhile, например, у вас будет цепочка, которая будет обрабатывать по одному элементу за раз.Теперь ваш первый оператор Where может явно отфильтровывать некоторые элементы, поэтому SkipWhile не будет видеть элемент, пока он не пройдет через предыдущий оператор.

Я лично предпочитаю разделять операторы для ясности и объединять их только в случае производительности.становится проблемой.

2 голосов
/ 03 февраля 2010

Использование Where и SkipWhile не приводит к «повторному просмотру коллекции». LINQ to Objects работает по модели pull. Когда вы перечисляете комбинированный запрос, SkipWhile начнет запрашивать у его источника элементы. Его источником является Где, так что это заставит Где начать по очереди запрашивать у своего источника элементы. Таким образом, SkipWhile будет видеть все элементы, которые проходят предложение Where, но получает их по ходу. В результате LINQ выполняет foreach над исходной коллекцией, возвращая только те элементы, которые проходят оба фильтра Where и SkipWhile - и это включает в себя только один проход по коллекции.

Может быть банальная потеря эффективности, потому что задействованы два итератора, но это вряд ли будет значительным. Вы должны написать код, который будет понятен (как вы делаете в данный момент), и если вы подозреваете, что чистая версия вызывает проблемы с производительностью, убедитесь, что , и только затем попытайтесь объединить предложения .

1 голос
/ 03 февраля 2010

Нет, (по существу) нет снижения производительности. Вот что такое ленивое (отложенное) выполнение.

...