2016-10-11 17 views
3

まず、この質問がこのコミュニティに適合するかどうかはわかりません。それはそれをどこに移動するには:)パフォーマンスの違い/カスタムLinq拡張による改善

をだから、私に教えてくださいしていない場合、私は自分自身が非常に頻繁にこのようにLINQの式を書いてキャッチしました:

var xy = someSource.Where(x => x.Property == value).Select(x => new Y(x)); 

私のコードをリファクタリングするとき、私は、これは実際に私を列挙思いましたソースは二回、私はこの小さな拡張(実際には、あまりにも何も特別な)を書いた:

public static IEnumerable<TResult> SelectWhere<TIn, TResult>(this IEnumerable<TIn> source, 
     Func<TIn, bool> predicate, Func<TIn, TResult> selector) 
    { 
     foreach (var item in source) 
     { 
      if (predicate(item)) 
      { 
       yield return selector(item); 
      } 
     } 
    } 

だから私は

var xy = someSource.SelectWhere(x => x.Property == value, x => new Y(x)); 
と私のクエリを置き換えることができます210

もちろん、ソースの列挙型が大きい場合や、それぞれの「次へ移動」に時間がかかる場合は、パフォーマンスが大幅に向上します(まったくの場合)。

私の質問は次のとおりです。パフォーマンス(やや)、この拡張機能を持つ価値はありますか?

+2

「私はこれが実際に私のソースを2回列挙したと思ったのですが、どうしてそう思いますか? –

+0

私はそう思っています。なぜなら、 'Where'と' Select'の両方が彼らの行動を実行するために列挙する必要があるからです。 – Stefan

+0

@Stefan:いいえ、 'Where'と' Select'は* lazy *ですが、列挙する必要はありません。 –

答えて

5

LINQと列挙型は設計によって遅延しています。つまり、結果コレクションからアイテムを実際に要求するときにソースコレクションのみを反復することを意味します。

だから、その後、Select transformatorに直接渡され、あなたのWhere式を、一致するものに当たるまで、あなたのxyから一つの要素だけのオリジナルsomeSourceからアイテムを取得します取得。それは実際に一度に1つのアイテムだけを評価します。あなたがここにパイプラインを想像する必要があります。

xyからアイテムを要求する反復可能ではイテレータが元iterable-からアイテムを要求しますWhereのiterableからそのイテレータ要求項目を作るのiterable Selectからxyイテレータ要求項目を作ります一度に1つのアイテム。

これは、列挙型を非常に怠惰にします(パフォーマンスには非常に優れています)が、チェーン内のさまざまなイテレータを管理するオーバーヘッドが少し追加されます。チェーンが長くなればなるほどオーバーヘッドがある。

一般に、これらの操作を最適化する理由はほとんどありません。 LINQはすぐにボトルネックにならないほど速く、コードをプロファイリングすることで実際にアプリケーションのボトルネックと認識しない限り、コードを最適化するための努力はしないでください。これは、LINQが非常に読みやすく、容易に従うことを目指しているため、LINQにとって特に当てはまります。

もちろん、一般的なLINQ操作の組み合わせに対して追加の拡張機能を追加することもできますが、1つのイテレータを削除するとパフォーマンスが向上することに気付かないでしょう。

LINQ式がボトルネックですが、可読性の理由からLINQ式を書き続けたい場合は、roslyn-linq-rewriteを参照してください。 Roslynベースのツールで、コンパイル時にLINQ式を手続き型コードに書き換えて、LINQ式の犠牲を犠牲にせずに超効率的にします。

+0

素敵な説明:) 正直言って私はLinqのメカニズムにはまだ潜んでいませんでした。 これは私の拡張機能をかなり役に立たなくする – Stefan

1

Linq WhereおよびSelectは、1つの列挙で処理されています。

これは、1つの列挙になり:

var xy = someSource.Where(x => x.Property == value).Select(x => new Y(x));

ここで最適化するので、何もありません。

関連する問題