"Zagnieżdżone foreach "vs" lambda/LINQ query " performance (LINQ-to-Objects) [closed]

zamknięte . To pytanie musi być bardziej skoncentrowane . Obecnie nie przyjmuje odpowiedzi.

chcesz poprawić to pytanie? Update the question so it edytując ten post.

Zamknięte 4 lata temu .

Popraw to pytanie

W performance point of view co należy użyć" zagnieżdżonych zapytań foreach ' s "lub" lambda/linq queries"?

Author: JSC, 2009-06-25

5 answers

Napisz najczystszy kod, jaki możesz, a następnie porównaj i profiluj, aby odkryć wszelkie problemy z wydajnością. Jeśli masz problemy z wydajnością, możesz poeksperymentować z innym kodem, aby dowiedzieć się, czy jest szybszy, czy nie (mierzenie przez cały czas z jak najbardziej realistycznymi danymi), a następnie dokonać oceny, czy poprawa wydajności jest warta trafienia czytelności.

Bezpośrednie podejście foreach będzie szybsze niż LINQ w wielu przypadkach. Na przykład, rozważmy:

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);
}

Teraz są dwie klauzule where i klauzula select, więc każdy ewentualny element musi przejść przez trzy Iteratory. (Oczywiście dwa, gdzie klauzule mogą być połączone w tym przypadku, ale robię ogólną uwagę.)

Teraz porównaj go z kodem bezpośrednim:

foreach (var element in list)
{
    if (element.X > 2 && element.Y < 2)
    {
        Console.WriteLine(element.X + element.Y);
    }
}
To będzie działać szybciej, ponieważ ma mniej obręczy do przejechania. Są szanse, że wyjście konsoli zmniejszy koszt iteratora, a ja na pewno wolę LINQ zapytanie.

EDIT: odpowiedź na temat zagnieżdżonych pętli foreach... zazwyczaj są one reprezentowane przez SelectMany lub drugą from klauzulę:

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

Tutaj dodajemy tylko jeden dodatkowy iterator, ponieważ będziemy już używać dodatkowego iteratora na element w pierwszej sekwencji ze względu na zagnieżdżoną pętlę foreach. Jest jeszcze trochę narzutu, w tym narzutu z robienia projekcji w delegacie zamiast " inline "(o czym wcześniej nie wspomniałem), ale nadal nie będzie bardzo różnie do wykonania zagnieżdżonego-foreach.

To nie znaczy, że nie możesz strzelić sobie w stopę LINQ, oczywiście. Możesz pisać zdumiewająco nieefektywne zapytania, jeśli nie zaangażujesz najpierw swojego mózgu - ale to nie jest unikalne dla LINQ...

 63
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 14:42:25

If you do

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

Wykonasz klienta.Count * Order.Liczba iteracji


If you do

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
}

Wykonasz klienta.Licznik + Kolejność.Policz iteracje, bo Wylicz.Join jest zaimplementowany jako HashJoin.

 24
Author: Amy B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 14:31:09

To bardziej skomplikowane. Ostatecznie, wiele z LINQ-to-Objects jest (za kulisami) pętlą foreach, ale z dodanym nadmiarem trochę abstrakcji / bloków iteratora / itp. Jednak, o ile nie zrobisz zupełnie różnych rzeczy w swoich dwóch wersjach (foreach vs LINQ), obie powinny być O (N).

Prawdziwe pytanie brzmi: czy istnieje lepszy sposób napisania twojego specyficznego algorytmu , który oznacza, że foreach byłby nieefektywny? Czy LINQ może to zrobić za Ciebie?

Na przykład LINQ ułatwia hashowanie / grupowanie / sortowanie danych.

 13
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 14:29:01

To już zostało powiedziane, ale zasługuje na powtórzenie.

Programiści nigdy nie wiedzą, gdzie jest wąskie gardło wydajności, dopóki nie przeprowadzą testów wydajności.

To samo dotyczy porównania techniki A do techniki B. Jeśli nie ma dramatycznej różnicy, musisz ją po prostu przetestować. Może to być oczywiste, jeśli masz scenariusz O(n) vs O(N^x), ale ponieważ LINQ jest głównie kompilatorem, zasługuje na profilowanie.

Poza tym, chyba że twój projekt jest w produkcji i sprofilowałeś kod i stwierdziłeś, że ta pętla spowalnia Twoje wykonanie, pozostaw ją jako preferowaną czytelność i konserwację. Przedwczesna optymalizacja to diabeł.

 2
Author: Drithyin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 14:43:23

Wielką zaletą jest to, że korzystanie z zapytań Linq-to-Objects daje możliwość łatwego przekazania zapytania do PLinq, a system automatycznie wykona operację na odpowiedniej liczbie wątków dla bieżącego systemu.

Jeśli używasz tej techniki na dużych zestawach danych, to łatwo stać się wielką wygraną dla bardzo małych problemów.

 2
Author: Denis Troller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 14:44:00