Что делает предложение LINQ to objects 'where' за кулисами? - PullRequest
5 голосов
/ 20 марта 2009

Я только что заменил этот кусок кода:

foreach( var source in m_sources )
{
    if( !source.IsExhausted )
    {
        ....
    }
}

с этим:

foreach( var source in m_sources.Where( src => !src.IsExhausted ) )
{
   ...
}

Теперь код выглядит лучше (для меня), но мне интересно, что на самом деле здесь происходит. Я обеспокоен производительностью в этом случае, и было бы плохо, если бы применение этого фильтра означало, что произойдет какая-то магия компилятора.

Два куска кода делают в основном одну и ту же вещь? Созданы ли временные контейнеры для фильтрации и передачи их моему foreach?

Любая помощь по этому вопросу будет в значительной степени оценена. Спасибо.

Ответы [ 3 ]

6 голосов
/ 20 марта 2009

Ключевое слово yield return и лямбда-выражения включают в себя создание скрытых классов во время компиляции и выделение дополнительных объектов во время выполнения, и если ваш фон находится в C или C ++, то естественно беспокоиться о производительности.

Естественно, но неправильно!

Я попытался измерить накладные расходы для лямбд с замыканием по локальным переменным, и обнаружил, что он настолько невероятно мал (вопрос наносекунд), что он не будет иметь значения почти во всех приложениях. *

2 голосов
/ 20 марта 2009

Это зависит от типа, если m_sources.

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

Если это IEnumerable, то Where в значительной степени реализован как:

public static IEnumnerable<T> Where(this IEnumerable<T> input, Func<T, bool> predicate) {
  foreach (var v in input) {
    if (predicate(v)) {
      yield return v;
    }
  }
}

Это довольно эффективно и работает лениво (поэтому, если вы рано выйдете из цикла, предикат не будет применен ко всей коллекции).

1 голос
/ 20 марта 2009

В принципе, да, это то же самое, O (n).

Предложение where будет выполнено во время цикла по списку (т. Е. Если вы разбиваете после первого элемента, следующие элементы не будут проверяться).

...