У запросов LINQ много накладных расходов?

Простые запросы LINQ на IEnumerable<T> в легком или тяжелом весе? Как они сравниваются с написанием стрелок for или foreach вручную? Есть ли общее правило, когда следует предпочитать LINQ или ручной поиск?

Например:

var lowNums =
    from n in numbers
    where n < 5
    select n;

По сравнению с:

List<int> lowNums = new List<int>();

foreach (int n in numbers)
{
    if (n < 5)
    {
        lowNums.Add(n);
    }
}

Я разговаривал с коллегой о LINQ, и он несколько раз размышлял об использовании этого. Он предположил, что "за кулисами" может быть много, чтобы поддержать все, что может сделать LINQ.

Есть ли существенная разница в производительности между приведенными выше примерами? Есть ли хорошие ресурсы, которые говорят о производительности LINQ для коллекций? Простой поиск Google linq performance показал некоторые, казалось бы, устаревшие статьи.

Ответ 1

Авторы LINQ в действии провели несколько тестов с помощью for, foreach, List<T>.FindAll, а запросы LINQ сделали то же самое. В зависимости от того, как были построены запросы, LINQ был примерно на 10% медленнее. Как они выразились,

LINQ не приходит бесплатно.

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

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

Признание и краткость, которые он предлагает, намного превосходят любые соображения производительности для большинства моих повседневных кодировок. Никогда не оптимизируйте!

Ответ 2

Вот мое общее правило для LINQ

Используйте LINQ, когда решение более выразительно. Только переключитесь на менее выразительное, но более быстрое решение, когда профилировщик доказал, что запрос LINQ является источником проблемы.

Ответ 3

Там накладные расходы на вызовы делегатов, но в целом довольно низкие.

Тогда есть накладные расходы всех задействованных итераторов - обычно один итератор на добавочное предложение в запросе. Опять же, не огромное количество, но и ничего.

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

Обратите внимание, что производительность в вашем примере совсем другая, потому что две части кода делают совсем другие вещи. Ваш пример LINQ будет выполняться мгновенно, потому что он фактически не выполняет запрос - он просто настраивает его. Если вы вызываете ToList() в конце, это в основном эквивалентно вашему второму примеру. Такие вещи очень важны для запоминания при выполнении сравнений производительности!

Еще одна вещь, о которой нужно помнить - вам не нужно использовать синтаксис выражения запроса. Если вы просто фильтруете (или просто проецируете), я обычно нахожу, что имеет смысл называть метод расширения обычной нотной меткой:

var lowNums = numbers.Where(n => n < 5);

Ответ 4

О единственной реальной накладной производительности LINQ-to-objects над ее выполнением - это несколько дополнительных объектов, созданных для помощи в перечислении и вызовах функций. Короче говоря, если вы не используете его таким образом, чтобы он не был разработан, это не повредит вашей работе, если вы не делаете очень высокопрофессиональный материал.

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

Ответ 5

В соответствии с LINQ in Action (pg.198):

"LINQ не поставляется бесплатно. LINQ запросы вызывают дополнительную работу, объект творениями и давлением на мусор коллектор. Дополнительные расходы использование LINQ может сильно варьироваться в зависимости от запрос. Это может быть всего лишь 5 процентов, но иногда может быть 500 процентов".

Ответ 6

Один отличный способ убедить себя в LINQ - использовать LINQPad. Он позволяет выводить IL для ваших реализаций LINQ и не LINQ (а также выводить SQL, если вы используете LINQ2SQL).

Часто, когда у меня возникает вопрос о том, что именно происходит "за кулисами" (как удивляется ваш коллега), я иду в ИЛ и узнаю для себя. Подавляющее большинство времени, что я видел, это то, что LINQ immenetation превосходна.