2009-06-25 18 views

答えて

55

可能な限り明確なコードを作成し、ベンチマークとプロファイルを使用してパフォーマンスの問題を発見してください。 の場合にはパフォーマンス上の問題があります。異なるコードで試して、速いかどうかを試してみてください(できるだけ現実的なデータで常に測定しています)。そしてパフォーマンスの向上が価値あるものかどうかを判断してください読みやすさに打撃を与えた

直接foreachのアプローチは、多くの場合、LINQより高速であることがあります。たとえば、考えてみます。

var query = from element in list 
      where element.X > 2 
      where element.Y < 2 
      select element.X + element.Y; 

foreach (var value in query) 
{ 
    Console.WriteLine(value); 
} 

今すぐ2 where節と select句があるので、すべての最終的な項目は3つのイテレータを通過しなければなりません。

foreach (var element in list) 
{ 
    if (element.X > 2 && element.Y < 2) 
    { 
     Console.WriteLine(element.X + element.Y); 
    } 
} 

それは持っているので、より速く実行されます:(。明らか節は、この場合に組み合わせることができる2、私は一般的なポイントを作ってるんだ)

今すぐ直接コードとそれを比較します逃げようとする人の数が少なくなります。コンソールの出力がイテレータのコストを犠牲にする可能性があり、LINQクエリーを好むでしょう。

EDIT:「入れ子になったのforeach」について答えるためにループする...一般的に、これらはSelectMany又は第二from句で表現されています。私たちは「ので

var query = from item in firstSequence 
      from nestedItem in item.NestedItems 
      select item.BaseCount + nestedItem.NestedCount; 

ここでは唯一、単一の余分なイテレータを追加していますすでにネストされたforeachループのために、最初のシーケンスでアイテムごとに余分なイテレータを使用しています。そこの代わりに「インライン」(私は前に言及しなかった何か)のデリゲートで投影を行うためのオーバーヘッドを含むオーバーヘッドのビットは、まだだが、それはまだネストされた-foreachの性能に非常に異なることはありません。

もちろん、LINQで足で自分を撃つことはできないとは限りません。脳を最初に関与させないと、非常に非効率なクエリを書くことができますが、それはLINQ独自のものではありません。

+13

最初の文章はバナーとして印刷し、すべてのプログラミング部門にぶら下げてください。 –

+1

ジョン...あなたは素晴らしいです...心から感謝!! –

11

これはもっと複雑です。あなたはLINQ対あなたの二つのバージョン(foreachの中で非常に異なることを行う場合を除き、最終的に、LINQツーオブジェクトの多くは、しかし、(舞台裏)foreachループですが、少し抽象/反復子ブロック/などの追加のオーバーヘッドで)、両方ともO(N)でなければなりません。

本当の問題は、次のとおりです。foreachは非効率的になることを意味し、あなたの特定アルゴリズムを書くのより良い方法はありますか?そしてLINQはあなたのためにそれをすることができますか?

たとえば、LINQを使用すると、データを簡単にハッシュ/グループ化/ソートできます。

22

あなたは

foreach(Customer c in Customer) 
{ 
    foreach(Order o in Orders) 
    { 
    //do something with c and o 
    } 
} 

を行う場合は、Customer.Count *注文を実行します。Enumerable.Joinはハッシュ結合として実装されているので、あなたが

var query = 
    from c in Customer 
    join o in Orders on c.CustomerID equals o.CustomerID 
    select new {c, o} 

foreach(var x in query) 
{ 
    //do something with x.c and x.o 
} 

あなたはCustomer.Count + Order.Countの繰り返しを行います行う場合は、反復


を数えます。

+0

良い解説付き素晴らしい答え –

+4

これは、2つの異なるアルゴリズムを実行しているためです。あなたはリンゴとオレンジを比較しています。私はこれが提起された問題にどのように関連しているのか分かりません。 – mquander

+3

あなたのネストされたforeachは、実際にSelectManyと同じです。つまり、Joinではなく、oのCustomerからoから... join(no join) –

2

これまでに言われていますが、それは繰り返すことができます。

開発者は、パフォーマンステストを実行するまで、パフォーマンスのボトルネックがどこにあるか決して分かりません。

テクニックAとテクニックBを比較する場合も同じです。劇的な違いがない限り、テストするだけです。 O(n)vs O(n^x)のシナリオがあるのは明らかですが、LINQの内容は主にコンパイラの魔術術であるため、プロファイリングのメリットがあります。

さらに、プロジェクトが実稼働していて、コードをプロファイリングしてループが実行速度を遅くしていることが判明していない場合は、可読性とメンテナンスのどちらを優先しても問題ありません。時期尚早の最適化は悪魔です。

+1

パフォーマンスのボトルネックを真に予測することはできませんが、ほとんどのパフォーマンスの問題は設計されており、開発ライフサイクルの非常に遅れているため、コード化することは困難です。あなたが作っている設計と実装の決定のパフォーマンスへの影響をいつでも目の当たりにすることができれば、それは大丈夫だろうと思っています。 – Mike

2

Linq-To-Objectsクエリを使用すると、クエリーをPLinqに簡単に切り替えて、システムが現在のシステムの正しいスレッド数で自動的にオペレーションを実行できるようになります。

このテクニックを大きなデータセットで使用している場合は、簡単にはほとんど問題なく大きな勝利になります。

+0

真ですが、foreachにも同様の方法が提案されています。 http://www.danielmoth.com/Blog/2009/01/parallelising-loops-in-net-4.html – jpierson

関連する問題