さまざまなラムダ式の構文を使用して、パフォーマンスの違いをテストしています。簡単な方法がある場合:
public IEnumerable<Item> GetItems(int point)
{
return this.items.Where(i => i.IsApplicableFor(point));
}
point
ラムダの観点からは自由変数であるため、パラメータに関連する変数リフティングがここで行われています。このメソッドを 100 万回呼び出すとしたら、そのままにしておくか、何らかの方法で変更してパフォーマンスを向上させる方がよいでしょうか?
どのようなオプションがあり、どれが実際に実行可能ですか? 私が理解しているように、フリー変数を取り除く必要があるため、コンパイラはクロージャ クラスを作成して、このメソッドを呼び出すたびにインスタンス化する必要がありません。通常、このインスタンス化には、非クロージャ バージョンと比較してかなりの時間がかかります。
問題は、大ヒットのラムダ式を書くたびに時間を無駄にしているように見えるので、一般的に機能するある種のラムダ記述ガイドラインを考え出したいということです。従うべきルールがわからないため、動作することを確認するために手動でテストする必要があります。
代替方法
& サンプル コンソール アプリケーション コード
また、変数のリフティングを必要としない同じメソッドの別のバージョンも作成しました (少なくともそうではないと思いますが、これを理解している皆さんは、その場合はお知らせください)。
public IEnumerable<Item> GetItems(int point)
{
Func<int, Func<Item, bool>> buildPredicate = p => i => i.IsApplicableFor(p);
return this.items.Where(buildPredicate(point));
}
ここで要旨をチェックしてください。コンソール アプリケーションを作成し、コード全体をブロックProgram.cs
内のファイルにコピーするだけです。namespace
2 番目の例は、自由変数を使用していませんが、はるかに遅いことがわかります。
矛盾した例
ラムダの最適な使用ガイドラインを作成したい理由は、以前にこの問題に遭遇したことがあり、驚いたことに、述語ビルダーのラムダ式を使用すると、より高速に動作することが判明したためです。
では、それを説明してください。コードに頻繁に使用するメソッドがあることがわかっている場合、ラムダをまったく使用しないことが判明する可能性があるため、ここで完全に迷っています。でも、そんな事態は避けて、真相を究明したい。
編集
あなたの提案はうまくいかないようです
コンパイラが自由変数ラムダで行うのと同様に内部的に動作するカスタム ルックアップ クラスを実装しようとしました。ただし、クロージャー クラスを使用する代わりに、同様のシナリオをシミュレートするインスタンス メンバーを実装しました。これはコードです:
private int Point { get; set; }
private bool IsItemValid(Item item)
{
return item.IsApplicableFor(this.Point);
}
public IEnumerable<TItem> GetItems(int point)
{
this.Point = point;
return this.items.Where(this.IsItemValid);
}
興味深いことに、これは遅いバージョンと同じくらい遅く動作します。理由はわかりませんが、速いもの以外は何もしていないようです。これらの追加メンバーは同じオブジェクト インスタンスの一部であるため、同じ機能を再利用します。ともかく。私は今、非常に混乱しています!
この最新の追加でGist ソースを更新したので、自分でテストできます。