Laden...

Linq langsamer als normale Schleife?

Erstellt von Schildkroete vor 10 Jahren Letzter Beitrag vor 10 Jahren 3.000 Views
S
Schildkroete Themenstarter:in
80 Beiträge seit 2012
vor 10 Jahren
Linq langsamer als normale Schleife?

Hallo zusammen,

bei mir hat sich eine Frage aufgetan: Ist Linq wirklich langsamer als eine normale Schleife?

Wenn man eine Collectionlist mit n Elementen erzeugt, die Elemente können von Typ String sein, mit unterschiedlicher Länge und man will heraus finden, ob die Elemente in der Liste die Länge x überschreiten, so arbeitet die normale Schleife in zwei Fällen schneller als Linq.

Fall 1: Man interiert über die gesamte Liste und sortiert die Elemente heraus, die die Länge x überschreiten, danach schaut man, ob die neue Liste eine Array Größe größer 0 hat und gibt entweder True oder False raus.

Fall 2: Man interiert über die Liste und sobald ein Element gefunden wurde, das die Größe x überschreitet, so wird die Schleife abgebrochen und und es wird ein True zurück gegeben.

Wenn man im Fall 1 und Fall 2 Linq einsetzt, entweder mit filtere die Liste und gibt mir den Count oder mit dem Aufruf der Funktion Any( o => o.Length > x), so ist der Faktor meistens um 2 oder sogar um 10 größer.

Oder gibt es Ansätze, dass man Linq bei simplen Filteraufgaben nicht unbedingt einsetzen sollte, sondern bei komplexeren Aufgaben?

----ehm............

16.835 Beiträge seit 2008
vor 10 Jahren

Du solltest eher Fragen: ist Linq wirklich schneller als eine Schleife.
Und die Antwort ist: in 98% der Fälle ja

Was in LINQ eben nicht so einfach geht ist ein vorzetiger Abbruch; dadurch kostet Dich LINQ in diesem konkreten Fall eben Performance.

S
Schildkroete Themenstarter:in
80 Beiträge seit 2012
vor 10 Jahren

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqLoopTest
{
	class Program
	{
		static void Main(string[] args)
		{
			Console.WriteLine("Measure first pathlist");

			List<String> PathList1 = CreatePathList1();
			MeasureLinq(PathList1);
			MeasureLoopWithCount(PathList1);
			MeasureLoopWithBreak(PathList1);

			Console.WriteLine("");
			Console.WriteLine("Measure second pathlist");

			List<String> PathList2 = CreatePathList2();
			MeasureLinq(PathList2);
			MeasureLoopWithCount(PathList2);
			MeasureLoopWithBreak(PathList2);

			Console.ReadKey();
		}

		private static bool MeasureLinq(List<String> PathList)
		{
			Stopwatch sw = new Stopwatch();

			sw.Start();
			//bool LongPathFound = (PathList.Where(p => p.Length > 0).Count() > 0);	
            bool LongPathFound = PathList.Any(Path => Path.Length > 0);
			sw.Stop();

			Console.WriteLine("Time for MeasureLinq:\t\t" + sw.ElapsedTicks);

			return LongPathFound;
		}

		private static bool MeasureLoopWithCount(List<String> PathList)
		{
			Stopwatch sw = new Stopwatch();

			sw.Start();
			List<String> TempList = new List<string>();
			foreach (String Path in PathList)
			{
				if (Path.Length > 0)
					TempList.Add(Path);
			}
			bool LongPathFound = (TempList.Count > 0);
			sw.Stop();

			Console.WriteLine("Time for MeasureLoopWithCount:\t" + sw.ElapsedTicks);

			return LongPathFound;
		}

		private static bool MeasureLoopWithBreak(List<String> PathList)
		{
			Stopwatch sw = new Stopwatch();

			sw.Start();
			bool LongPathFound = false;
			foreach (String Path in PathList)
			{
				if (Path.Length > 0)
				{
					LongPathFound = true;
					break;
				}
			}
			sw.Stop();

			Console.WriteLine("Time for MeasureLoopWithBreak:\t" + sw.ElapsedTicks);

			return LongPathFound;
		}

		private static List<String> CreatePathList1()
		{
			List<String> PathList = new List<string>();
			for (int i = 1; i <= 99900; i++)
				PathList.Add(String.Empty);

			for (int i = 1; i <= 100; i++)
				PathList.Add(" ");

			return PathList;
		}

		private static List<String> CreatePathList2()
		{
			List<String> PathList = new List<string>();
			for (int i = 1; i <= 100000; i++)
			{
				if (i % 1000 == 0)
					PathList.Add(" ");
				else
					PathList.Add(String.Empty);
			}
			return PathList;
		}
	}
}

----ehm............

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Schildkroete,

Faktor 2 oder 10 sagt doch noch gar nichts über die Gesamtlaufzeit, auf die es normalerweise einzig ankommt. Ob eine Aktion 2µs oder 20µs dauert, ist mir als Benutzer doch vollkommen egal. Viel wichtiger als die Performance ist die Lesbarkeit des Codes. Verfalle nicht in "premature optimization", denn das ist bekanntermaßen "the root of all evil".

Siehe auch foreach oder for? was ist schneller? Ist die Reihenfolge festgelegt?

herbivore

16.835 Beiträge seit 2008
vor 10 Jahren

Verwende bei List<T> Count statt Count()
Count() erfordert einen nochmaligen Durchlauf der Liste => ziemlich unperformant hier.

Das war auf den kommentierten Code bezogen

S
Schildkroete Themenstarter:in
80 Beiträge seit 2012
vor 10 Jahren

@Alle
Danke für die Aussagen. Der Grund für diesen Thread ist wie immer, zwei Programmierer (einer älter der andere jung) zanken sich um Code und Performance.

Der Code ist nur ein Beispiel und wurde nicht von mir, sondern von meinem Kollegen erstellt. Er mag nicht, wenn ich Linq verwende, obwohl viele Entwickler dafür sprechen.

----ehm............

1.346 Beiträge seit 2008
vor 10 Jahren

Verwende bei List<T> Count statt Count()
Count() erfordert einen nochmaligen Durchlauf der Liste => ziemlich unperformant hier.

Das stimmt nicht so ganz. Count() gibt ICollection<T>.Count zurück falls es sich um eine ICollection<T> handelt, sonst ICollection.Count, und wenn es auch keine ICollection ist wird erst iteriert. Da List<T> ICollection<T> implementiert wird bei eine List also nicht iteriert, sondern intern auf Count zurückgegriffen

LG pdelvo

16.835 Beiträge seit 2008
vor 10 Jahren

Sowas würde ich typischerweise mit "Wer nicht mit der Zeit geht, geht mit der Zeit" beantworten, was aber durchaus gern das Feuer erst richtig entfacht.
Linq ist eine unheimlich performante Variante Elemente von Daten zu präsentieren und zu suchen - man muss es aber bedienen wissen.
herbivores Einwand bezüglich der Wartbarkeit sei hier also gegeben - aber wer sich mit der Materie auskennt der wird einiges an Performance rausholen - jedoch nicht überall.

Danke pdelvo für die Präzesierung.

849 Beiträge seit 2006
vor 10 Jahren

Liege ich eigentlich falsch wenn ich sage das dieser Thread wieder einmal Linq mit Lambda Expressions durcheinander wirft?

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo unconnected,

naja, die Any Methode, die in MeasureLinq gemessen wird, ist wie Where, OrderBy usw. auch eine Erweiterungsmethode aus der Klasse Enumerable aus dem Namespace System.Linq. Je nachdem, wie man die Frage Was genau ist LINQ? - die wir hier nicht noch einmal aufrollen sollten - beantwortet, kann man es schon als Frage zu Linq betrachten. Jedenfalls geht es nicht nur um Lambda-Ausdrücke.

herbivore