“Вложенные foreach” по сравнению с “lambda/linq запрашивают” производительность [закрытый] (LINQ к объектам)

<ul>
    <li ng-repeat="item in items | filter:keyword as filteredItems">
        ...
    </li>
    <li ng-if="filteredItems.length===0">
        No items found
    </li>
</ul>

Это похоже на @Konrad 'ktoso' Malawski, но немного легче запомнить.

Протестировано с Angular 1.4

37
задан JSC 25 June 2009 в 14:22
поделиться

5 ответов

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

Прямой подход foreach во многих случаях будет быстрее, чем LINQ. Например, рассмотрим:

var query = from element in list
            where element.X > 2
            where element.Y < 2
            select element.X + element.Y;

foreach (var value in query)
{
    Console.WriteLine(value);
}

Теперь есть два предложения where и предложение select , поэтому каждый конечный элемент должен пройти через три итератора. (Очевидно, что в этом случае можно было бы объединить два предложения where, но я делаю общий вывод.)

Теперь сравните его с прямым кодом:

foreach (var element in list)
{
    if (element.X > 2 && element.Y < 2)
    {
        Console.WriteLine(element.X + element.Y);
    }
}

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

РЕДАКТИРОВАТЬ: Чтобы ответить о «вложенных циклах foreach» ... обычно они представлены с помощью SelectMany или второй из предложения :

var query = from item in firstSequence
            from nestedItem in item.NestedItems
            select item.BaseCount + nestedItem.NestedCount;

Здесь мы добавляем только один дополнительный итератор, потому что мы уже использовали бы дополнительный итератор для каждого элемента в первой последовательности из-за вложенного цикл foreach . По-прежнему есть небольшие накладные расходы, включая накладные расходы на выполнение проекции в делегате вместо "встроенного" (о чем я не упоминал раньше), но это все равно не будет сильно отличаться от производительности вложенного foreach.

Это не значит, что ты можешь » С LINQ, конечно, стрелять себе в ногу. Вы можете писать чрезвычайно неэффективные запросы, если сначала не задействуете свой мозг - но это далеко не уникально для LINQ ...

59
ответ дан 27 November 2019 в 04:17
поделиться

Если вы выполните

foreach(Customer c in Customer)
{
  foreach(Order o in Orders)
  {
    //do something with c and o
  }
}

, вы выполните итерации Customer.Count * Order.Count


Если вы выполните

var query =
  from c in Customer
  join o in Orders on c.CustomerID equals o.CustomerID
  select new {c, o}

foreach(var x in query)
{
  //do something with x.c and x.o
}

, вы выполните итерации Customer.Count + Order.Count, потому что Enumerable .Join реализован как HashJoin.

23
ответ дан 27 November 2019 в 04:17
поделиться

Это более сложный вопрос. В конечном счете, большая часть LINQ-to-Objects (за кулисами) представляет собой цикл foreach , но с дополнительными накладными расходами в виде небольших блоков абстракции / итератора / и т. Д. Однако, если вы не делаете совсем другие вещи в своем две версии (foreach против LINQ), обе должны быть O (N).

Реальный вопрос: есть ли лучший способ написать свой конкретный алгоритм, который означает, что foreach будет неэффективным? Может ли LINQ сделать это за вас?

Например, LINQ упрощает хэширование / группировку / сортировку данных.

11
ответ дан 27 November 2019 в 04:17
поделиться

Об этом уже говорилось, но стоит повторить.

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

То же самое можно сказать и о сравнении техники А с техникой Б. Если нет существенной разницы, вам просто нужно ее проверить. Это может быть очевидно, если у вас есть сценарий O (n) vs O (n ^ x), но поскольку материал LINQ в основном является колдовством компилятора, он заслуживает профилирования.

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

2
ответ дан 27 November 2019 в 04:17
поделиться

Большим преимуществом является то, что использование запросов Linq-To-Objects дает вам возможность легко переключить запрос в PLinq и заставить систему автоматически выполнять операцию с правильным количеством потоков для текущая система.

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

2
ответ дан 27 November 2019 в 04:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: