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