なぜLINQ .Where(predicate).First() は .First(predicate) よりも速いのですか?
質問
パフォーマンステストを行っていて、次のようなLINQ式があることに気づきました。
result = list.First(f => f.Id == i).Property
よりも遅いです。
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);
}
どのように解決するのですか?
where+firstの方がfirstより早いという同じ結果を得ました。
Jonが指摘したように、Linqは遅延評価を使用するので、パフォーマンスは両方の方法でほぼ同じになるはずです(実際そうなっています)。
Reflector を見ると、First は単純な foreach ループを使用してコレクションを反復処理しますが、Where には異なるコレクション タイプ (配列、リストなど) に特化したさまざまなイテレータがあります。 おそらく、これが Where に小さな利点を与えています。
関連
-
[解決済み】IntPtrとは一体何なのか?
-
[解決済み] B "の印刷が "#"の印刷より劇的に遅いのはなぜですか?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] <は<=より速いのか?
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
-
[解決済み] LINQで.Firstと.FirstOrDefaultを使用するタイミングは?
-
[解決済み] なぜPythonのコードは関数の中でより速く実行されるのですか?
-
[解決済み] なぜJavaでは2 * (i * i)の方が2 * i * iより速いのですか?
-
[解決済み] なぜ[]はlist()よりも速いのですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】GDI+、JPEG画像をMemoryStreamに変換する際にジェネリックエラーが発生しました。
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】C# - パスに不正な文字がある場合
-
[解決済み] [Solved] 不正な文字列値: '\xEFxBFxBD' for column
-
[解決済み】Swashbuckle/Swagger + ASP.Net Core: "Failed to load API definition" (API定義の読み込みに失敗しました
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み】2年前のMSDateを把握する【クローズド
-
[解決済み】名前 'ViewBag' が現在のコンテキストに存在しない - Visual Studio 2015
-
[解決済み】Nullableオブジェクトは値を持たなければならない?