私はいくつかのパフォーマンステストを行うと、なぜLINQ.Where(述語).First()は.First(述語)より高速ですか?
result = list.First(f => f.Id == i).Property
のようなLINQの式はこれがカウンター直感的なようだ
result = list.Where(f => f.Id == i).First().Property
よりも低速であることに気づいています。私は.Where()
式は結果のサブセットに.First()
を呼び出す前に、リスト全体を反復処理するかもしれないと思っているだろう一方で、私は、それができるだけ早く述語が成立しているとして、リストを反復処理を停止することができますので、最初の式が速いだろうと思っているだろう。後者が短絡したとしても、Firstを直接使用するよりも速くすべきではありませんが、そうです。以下は
はこれを説明する2つの本当に簡単ユニットテストです。 TestWhereAndFirstで最適化してコンパイルすると、.NetとSilverlight 4でTestFirstOnlyより約30%高速です。私は述部をより多くの結果を返すように試みましたが、パフォーマンスの差は同じです。 .First(fn)
が.Where(fn).First()
より遅い理由
いずれかを説明できますか?私は.Count(fn)
と同様のカウンター直感的な結果を.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);
}
どのようにタイミングを取っていますか? –
あなたの最初の考えは間違っています:LINQは遅延計算を行います。したがって、 'First()'が呼び出されたときに、ただ1つの一致に対して( 'の返り値)' Where(...)をクエリし、したがって、「First(...)」(つまり、述語で直接)を呼び出すときとまったく同じ数の要素が調べられます。 – Jon
私は同じ結果を返します。 '.Where()。First()'は.021秒で '.First()'は.037秒です。これは 'int'の簡単なリストです。 – Ryan