Ich mache einige Leistungstests und habe festgestellt, dass ein LINQ-Ausdruck gefällt
result = list.First(f => f.Id == i).Property
ist langsamer als
result = list.Where(f => f.Id == i).First().Property
Dies scheint nicht intuitiv zu sein. Ich hätte gedacht, dass der erste Ausdruck schneller sein würde, da er die Iteration über die Liste beenden kann, sobald das Prädikat erfüllt ist, während ich gedacht hätte, dass der .Where()
Ausdruck die gesamte Liste durchlaufen könnte, bevor .First()
die resultierende Teilmenge aufgerufen wird. Selbst wenn letzterer einen Kurzschluss macht, sollte es nicht schneller sein als First direkt zu verwenden, aber es ist.
Im Folgenden finden Sie zwei wirklich einfache Komponententests, die dies veranschaulichen. Beim Kompilieren mit Optimierung auf TestWhereAndFirst ist es ungefähr 30% schneller als auf TestFirstOnly unter .Net und Silverlight 4. Ich habe versucht, das Prädikat dazu zu bringen, mehr Ergebnisse zurückzugeben, aber der Leistungsunterschied ist der gleiche.
Kann jemand erklären, warum .First(fn)
langsamer ist als .Where(fn).First()
? Ich sehe ein ähnliches kontraintuitives Ergebnis im .Count(fn)
Vergleich zu .Where(fn).Count()
.
private const int Range = 50000;
private class Simple
{
public int Id { get; set; }
public int Value { get; set; }
}
[TestMethod()]
public void TestFirstOnly()
{
List<Simple> list = new List<Simple>(Range);
for (int i = Range - 1; i >= 0; --i)
{
list.Add(new Simple { Id = i, Value = 10 });
}
int result = 0;
for (int i = 0; i < Range; ++i)
{
result += list.First(f => f.Id == i).Value;
}
Assert.IsTrue(result > 0);
}
[TestMethod()]
public void TestWhereAndFirst()
{
List<Simple> list = new List<Simple>(Range);
for (int i = Range - 1; i >= 0; --i)
{
list.Add(new Simple { Id = i, Value = 10 });
}
int result = 0;
for (int i = 0; i < Range; ++i)
{
result += list.Where(f => f.Id == i).First().Value;
}
Assert.IsTrue(result > 0);
}
quelle
First()
es aufgerufen wird,Where(...)
fragt es (den Rückgabewert von) nur nach einer Übereinstimmung und fragt niemals nach einer anderen. Es wird also genau die gleiche Anzahl von Elementen untersucht wie beim AufrufenFirst(...)
(dh direkt mit einem Prädikat)..Where().First()
ist .021 Sekunden und.First()
ist .037 Sekunden. Dies ist mit einer einfachen Liste vonint
s.Reset()
deine Stoppuhr nicht angerufen ; Ihr Test zeigt tatsächlich, dassFirst()
es deutlich schneller ist.Antworten:
Ich habe die gleichen Ergebnisse erzielt: wobei + first schneller war als first.
Wie Jon bemerkte, verwendet Linq eine verzögerte Bewertung, sodass die Leistung für beide Methoden weitgehend ähnlich sein sollte (und ist).
In Reflector verwendet First zunächst eine einfache foreach-Schleife, um die Sammlung zu durchlaufen. Dabei gibt es eine Vielzahl von Iteratoren, die auf verschiedene Sammlungstypen (Arrays, Listen usw.) spezialisiert sind. Vermutlich gibt dies Where den kleinen Vorteil.
quelle