Ist die LINQ-Version schneller als die foreach-Version?

75440
Jean-François Côté

Da ich nicht weiß, wie LINQ unter der Haube funktioniert, kann ich mich nicht entscheiden, welche Version sich am besten für die Schnelligkeit der Ausführung eignet . Ich habe einige Tests mit meinen Testdaten durchgeführt (Punktwolke), aber ich kann keinen klaren Unterschied zwischen den beiden erkennen. Das einzige, was ich weiß, ist, dass die realen Daten eine größere Punktwolke sein werden LINQ wäre schneller, aber dies ist nur dann der Fall, wenn LINQ nicht für jeden unter der Haube eine Funktion ausführt. In diesem Fall wären die beiden Funktionen gleich. Wie lautet dein Rat?

Übrigens cylindreist ein 3D-Zylinder und ich möchte wissen, welcher Punkt sich darin befindet.

Version 1 ohne LINQ

for (int i = 0; i < fpc.Vertices.Length; i++)
{
    if (cylindre.IsPointInside(fpc.Vertices[i]))
        listPoint.Add(fpc.Vertices[i]);
}

Version 2 mit LINQ

var insidePoint =
    from pt1 in fpc.Vertices
    where cylindre.IsPointInside(pt1)
    select pt1;

    foreach (Point3D pt2 in insidePoint)
    {
        listPoint.Add(pt2);
    }
Antworten
24
Dies könnte hilfreich sein: http://programmers.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil ANeves vor 8 Jahren 4
@ANeves Interessanter Artikel. Ich halte meine Frage nicht für verfrüht, da dies in der Anforderung und sehr wichtig ist, da sie von jedem Benutzer etwa 500 Mal am Tag durchgeführt wird. Und der einzige Grund, warum ich keine echten Daten habe, ist, dass das Endprodukt noch nicht fertig ist, aber ich bin mir sicher, dass es größer sein wird. Daher ist eine Optimierung in diesem Moment sehr wichtig. Ich erwäge auch eine andere Möglichkeit, die Funktion zu verbessern, aber der Unterschied zwischen linq und foreach war etwas, das mich interessiert. Jean-François Côté vor 8 Jahren 0
Haben Sie jedes Stück Leistung algorithmisch gequetscht? Welche Datenstrukturen und Algorithmen Sie verwenden, ist wichtig. Einige stark optimierte Bibliotheken für .Net führen einige Berechnungen schneller durch. Möglicherweise ist es auch möglich, PLINQ zu verwenden und mehrere Kerne gleichzeitig zu verwenden. Das würde ich auch messen. Leonid vor 8 Jahren 3
Danke für die Information. Tatsächlich haben wir eine sehr kleine Untermenge erstellt, mit der der foreach jetzt ausgeführt werden kann, denn er läuft mit LINQ und dem foreach sehr schnell. Jean-François Côté vor 8 Jahren 0
In der LINQ-Version können Sie `AddRange ()` anstelle von `foreach` erwägen. Die Leistung wird dadurch nicht gesteigert, der Code wird jedoch lesbarer. Die direkte Verwendung von "Where ()" ist kürzer als "from" / "where" / "select". svick vor 8 Jahren 1

4 Antworten auf die Frage

7
pstrjds

Wie gesagt wurde, ist die for-Schleife höchstwahrscheinlich performanter, aber Sie können den Code immer noch etwas bereinigen:

for (int i = 0; i < fpc.Vertices.Length; i++)
{
    if (cylindre.IsPointInside(fpc.Vertices[i]))
        listPoint.Add(fpc.Vertices[i]);
}

Kann werden:

foreach (var vertice in fpc.Vertices)
{
    if (cylindre.IsPointInside(vertice))
        listPoint.Add(vertice);
}

EDIT: Wie in der Performance-Frage. Dieser Code wird in LINQPad ausgeführt. Ich habe festgestellt, dass die foreach-Version einige Millisekunden besser ist als die for-Schleife.

var elements = Enumerable.Range(0, 4000000).Select(x => true).ToArray();


var sw = new Stopwatch();
var result = new List<bool>();
int trueCount = 0;
sw.Start();
for(int i=0; i < elements.Length; ++i)
{
    if (elements[i])
    {
        ++trueCount;
        result.Add(elements[i]);
    }
}

sw.Stop();
sw.ElapsedMilliseconds.Dump();

sw.Reset();
trueCount = 0;
result = new List<bool>();
sw.Start();
foreach(var element in elements)
{
    if (element)
    {
        ++trueCount;
        result.Add(element);
    }
}
sw.Stop();
sw.ElapsedMilliseconds.Dump();

EDIT2 - Bezüglich des Links, der auf eine so drastisch schlechte Leistung in einer Foreach-Schleife hindeutet

Der Link (http://www.schnieds.com/2009/03/linq-vs-foreach-vs-for-loop-performance.html) behandelt das Entfernen von Elementen aus einer Liste. Wenn Sie über eine generische Liste verfügen, ist das Entfernen von Elementen über eine for-Schleife normalerweise nicht die beste Lösung. Ein besserer Ansatz ist die Verwendung der RemoveAll- Methode. RemoveAll entfernt alle Elemente, die dem Prädikat entsprechen, und konsolidiert die Liste im Gegensatz zu RemoveAt, wodurch alle Elemente über dem entfernten Element verschoben werden müssen. Für den Leistungsvergleich der Entfernung finden Sie den folgenden Code (erneut kann dieser in LINQPad ausgeführt werden). In meinem Test lief die RemoveAll ca. 250x schneller.

var elements = Enumerable.Range(0, 100000).Select(x => x % 2 == 0).ToArray();

var sw = new Stopwatch();
var source = new List<bool>(elements);
sw.Start();
for(int i=0; i < source.Count; ++i)
{
    if (!source[i])
    {
        source.RemoveAt(i);
        --i;
    }
}

sw.Stop();
sw.ElapsedMilliseconds.Dump();
int count = source.Count;

sw.Reset();
source = new List<bool>(elements);

sw.Start();
source.RemoveAll((bool x) => {return x;});
sw.Stop();
sw.ElapsedMilliseconds.Dump();
Das Ersetzen der for-Schleife durch eine foreach-Funktion verringert die Leistung, wie in Xharze-Link http://www.schnieds.com/2009/03/linq-vs-foreach-vs-for-loop-performance.html angegeben Goldorak84 vor 8 Jahren 0
@ Goldorak84 - Wenn Sie sich das Codebeispiel für diesen Link anschauen, werden Sie feststellen, dass der Code sowohl im foreach- als auch im LINQ-Fall zweimal im Vergleich zu dem for-Fall gelaufen ist, der nur einmal in der Liste aufgeführt wurde. Dieser Link befasste sich mit dem Entfernen von Elementen aus einer Liste und hätte auch ohne Schleife mit [RemoveAll] (http://msdn.microsoft.com/en-us/library/wdka673a) geschrieben werden können. Dies wäre schneller als das for Schleife. pstrjds vor 8 Jahren 2
@pstrjds - Es tut mir leid, du hast absolut recht. Ich habe das Codebeispiel angepasst, um den Mechanismus zum Entfernen der foreach- und linq-Liste auf die for-Schleife anzuwenden. Der Unterschied zwischen for und foreach ist kaum spürbar. Goldorak84 vor 8 Jahren 0
5
Xharze

Unter der Haube durchläuft LINQ genau so wie die Kollektion foreach. Der Unterschied zwischen LINQ und foreach besteht darin, dass LINQ die Ausführung verschieben wird, bis die Iteration beginnt.

In Bezug auf die Leistung sollten Sie sich diesen Blogbeitrag ansehen .

Nur eine Anmerkung zu diesem Link. Der Link befasst sich mit dem Löschen von Elementen aus einer Liste. Es verwendet eine for-Schleife und kontrastiert diese mit einer doppelten foreach-Schleife und einer LINQ / foreach-Kombination. Nicht wirklich ein fairer Vergleich. pstrjds vor 8 Jahren 1
1
GabrielDR

Update:

If you're targeting .net 4 or later, you could use:

Parallel.ForEach()

or

RemoveAll().Parallel();

They should be faster than other methods.

`Liste.RemoveAll () `gibt ein" int "zurück, das die Anzahl der Elemente darstellt, die aus der Liste entfernt wurden. Meinten Sie `Liste.AsParallel () `? Mathieu Guindon vor 6 Jahren 1
0
Goldorak84

Ich glaube nicht, dass es unter LINQ schneller laufen wird. Die Funktion cylindre.IsPointInsidemüsste für jedes Element von Vertices noch aufgerufen werden.