2011-10-24 11 views
1

私は匿名のラムダが好きです。リストから複雑な選択肢を簡潔に表現できます。 LINQも同様のことをしているので、私はそれを試してみることにしました(ついに)。LINQと匿名のラムダパフォーマンス:それぞれを使用する場合

ラムダを頻繁に使用してコレクションのサブセットを選択する人は、いつLINQを使用すればよいですか、いつラムダを使うべきですか?this oneのような質問がありますが、いずれかの方法でパフォーマンスが10〜100倍異なることが示されています。

+2

最初のコードは '.ToArray()'を除いて2番目のコードと同じようにコンパイルされます。 – SLaks

+0

また、DateTime.Nowはこの種のベンチマークには十分正確ではありません。 – driis

+0

私はそこに顕著な意味の違い、ToArray呼び出しがあると思います。あなたがLINQの表現にそれを貼り付けたら、私は2つが近いと思うでしょう。 – heisenberg

答えて

5

LINQ評価が延期されています。 primesと​​の式は、コンパイラと同じです。どちらの場合でも、isOddAndNotDivisibleByは、何かが式の結果を評価するまで呼び出されません。この場合、cbの間のToArrayが強制的に評価されます。 abの間にToArrayを追加すると、同様の時間が得られます。

比較のために、あなたは試みることができる:

var primes = (
    from n in numbers 
    where isOddAndNotDivisibleBy(n) 
    select n).ToArray(); 
+0

これは〜10%の差にパフォーマンスを絞りました。しかし、どのような場合に使用するかは教えてくれません。ほとんどの場合、いくらか似たような性能を想定しています。 – ashes999

+0

違いは全くありません - 2つのバージョンは同等です(同じILにコンパイルされます)。あなたはどちらかがあなたに良く見えるものを使用します。 – Jimmy

+0

100倍のスピードアップでリンクされた質問は、ToArray()、ToList()、Count()などを最後に呼び出すのを忘れてしまったので、クエリを実行する必要はありませんでした。 – Jimmy

1

あなたのテストは同じではありません:あなたはbcToArray()を呼び出している、実際に実行した後にメモリを割り当てる(その後、再割り当て、その後、再割り当て)であろうあなたの質問。 ab

は、あなただけの実行、クエリを作成し、計算を実行します。 ToList()ToArray()を呼び出すか、foreachループ経由でクエリを反復処理すると、強制的に実行されます。クエリの理解の構文から、2回目のテストに一致する一連の拡張メソッドの呼び出しに変換されるため、ほぼ同じ時間がかかります。

最後に、タイミングにはDateTime.Nowを使用しないでください。 StopWatchを使用してください。

1

linqを実行しなかったので、primes .ToArray()を実行して比較してください。実際には、これは、LINQのdeffered execution動作です、それだけでクエリを作成し、それを実行しなかった、あなたには、いくつかの機能とそれを実行ゴマのような、foreachToList、...

また、両方のあなたは物事のは、LINQで、どちらもEnumerableクラスのIEnumerableにいくつかの拡張メソッドを使用しているため、最初はクエリ構文で、もう1つはドット表記構文です。 msdn linqでそれらを見てください。

3

"LINQ"と呼ばれるものは、実際にはLINQクエリ構文と呼ばれます。そして、あなたが "匿名のラムダ"と呼ぶものは、実際にはLINQのメソッド構文と呼ばれます。

numbers.Where(n => isOddAndNotDivisibleBy(n)) 

これは、あなたが直接、前者か後者を使用している場合、あなたは同じILコードを取得することを意味します:

from n in numbers 
where isOddAndNotDivisibleBy(n) 
select n 

が実際にコンパイルする前に、これに変換されます。重要なことは、表現ということです。

だから違いは別の場所にあるはずです。そしてそれはToArray()です。 Where()は怠惰です。つまり、実際に何らかの形で結果のシーケンスを反復しない限り、ほとんど何もしません。つまり、Where()と呼ぶだけですぐに迫ってくるはずです。しかし、ToArray()に電話すると、コレクションは実際に反復され、結果はすぐに計算されます。だから、あなたはそのような大きな違いを見るのです。

EDIT:他の上に1つの構文を使用する理由:変更された質問への

?主に、より読みやすいものを選択します。

は、クエリ構文(First()Aggregate()Concat()Zip()、インデックスを紹介過負荷、...)を使って表現することができないいくつかのメソッドとオーバーロードがあります。しかし、クエリの一部分と残りの部分にそれぞれ1つの構文を使用できます。

また、構文構文を使用して簡単に表現できない強力なクエリ構文の1つがあります。 let句を使用する場合。

しかし、2つの構文の間にパフォーマンスの違いはありません。これらの例

+0

LINQメソッド構文?私はあなたがドット表記法、またはメソッド連鎖構文を意味すると思います。 –

+0

それはMSがそれを呼んでいるものです:http://msdn.microsoft.com/en-us/library/bb397947.aspx – svick

+0

Microsoftはhttp://msdn.microsoft.com/en-us/library/bb308959 .aspxはドット表記法を示しています。メソッドのシンタックスも意味があります。メソッド連鎖パターン(http://en.wikipedia.org/wiki/Method_chainingを参照)があります。表記:)メソッド構文ではありません。 –

0

の両方が、確かに、同じLINQ を照会しますが、異なる構文砂糖とされています。

クエリとはどういう意味ですか? LINQクエリは、mySequence.Where(i => i > 5)または(from item in mySequence where item > 5)で作成するかどうかにかかわらず、格納される唯一のデータはシーケンスを列挙できることです。つまり、あなたの最初のクエリは評価されません - あなたToArrayまたはToListまたはToDictionaryまたはforeach、シーケンスはその後、あなたはこのような巨大なパフォーマンスのギャップを持っている理由である、評価され

。これまで

関連する問題