2016-05-24 11 views
1

次のキャッシュヘルパーは、キー名とクリエータ関数を取ります。キャッシュに名前付きオブジェクトがすでに含まれている場合はそれが返されます。そうでない場合は、作成者が呼び出されてオブジェクトが作成され、キャッシュに保持され、新しいオブジェクトが返されます。ラムダと別のメソッドとの性能差

public static T GetObject<T>(String name, Func<T> creator) { ... } 

明らかに、作成者関数は一度呼び出され(最初の時間)、他の999回は無視されます。

パフォーマンスにはどのような影響がありますか?これがちょうどメソッドポインタだった場合、私はそれが非常に些細なものになると考えています - 毎回スタックにポインタをプッシュするだけです - しかしラムダが高価な場合、おそらく状態付きのクロージャ - 実際に呼び出されるたびにこれはオブジェクトがすでに作成された後で(ラムダをスタック上にプッシュするだけで無視されます)。

これに代替する方法はありますか?

+1

面白い質問ですが、あなたのラムダがいかに「高価」であっても、パフォーマンスのヒットに気付くことはないでしょう。 –

+1

ラムダは実際には構文的な砂糖です。コンパイラは実際にメソッド/クラスを自動的に生成します(クロージャに応じて)。一度ILに着くと、それはほとんど同じコードです。 – Aron

+0

パフォーマンスの影響を知りたい場合は、コードをプロファイルして調べてください。あなたはすでにコードを書いています。それを実行します。 – Servy

答えて

2

最初にメソッドを実装してみましょう。その後、カバーの下で何が起こっているのか見ることができます。 GetObject(...)のための

private static Dictionary<string, object> _LUT; 

public static T GetObject<T>(String name, Func<T> creator) 
{ 
    object obj; 
    if (_LUT.TryGetValue(name, out obj)) 
    { 
     return (T)obj; 
    } 
    T ret = creator(); 
    _LUT.Add(name, ret); 
    return ret; 
} 

public string GetString(string name) 
{ 
    return GetObject<string>(name,() => "Foo"); 
} 

手順:GetStringメソッド(...)のための

IL_0000: ldsfld System.Collections.Generic.Dictionary`2[System.String,System.Object] _LUT 
IL_0005: ldarg.0 
IL_0006: ldloca.s System.Object (0) 
IL_0008: callvirt Boolean TryGetValue(System.String, System.Object ByRef) 
IL_000d: brfalse.s IL_0016 
IL_000f: ldloc.0 
IL_0010: unbox.any T 
IL_0015: ret 
IL_0016: ldarg.1 
IL_0017: callvirt T Invoke() 
IL_001c: stloc.1 
IL_001d: ldsfld System.Collections.Generic.Dictionary`2[System.String,System.Object] _LUT 
IL_0022: ldarg.0 
IL_0023: ldloc.1 
IL_0024: box T 
IL_0029: callvirt Void Add(System.String, System.Object) 
IL_002e: ldloc.1 
IL_002f: ret 

指示:

IL_0000: ldarg.1 
IL_0001: ldsfld System.Func`1[System.String] CS$<>9__CachedAnonymousMethodDelegate1 
IL_0006: brtrue.s IL_0019 
IL_0008: ldnull 
IL_0009: ldftn System.String <GetString>b__0() 
IL_000f: newobj Void .ctor(System.Object, IntPtr) 
IL_0014: stsfld System.Func`1[System.String] CS$<>9__CachedAnonymousMethodDelegate1 
IL_0019: ldsfld System.Func`1[System.String] CS$<>9__CachedAnonymousMethodDelegate1 
IL_001e: call System.String GetObject[String](System.String, System.Func`1[System.String]) 
IL_0023: ret 

あなたが見ることができるように、あなたのラムダはに格納されています型の静的フィールドSystem.Func1[System.String]

これは、参照することによってメソッドに渡されます(Why are delegates reference types?)、必要に応じてSystem.Func1[System.String].Invoke()を呼び出してください。したがって、メソッドのサイズに違いはありません。代替が存在するかどうかの質問については

これは一回限りの関数である場合は、System.Lazyを試みることができる、あなたは一般的なキャッシュのサポートを探しているなら、私はこれをチェックすることをお勧め:.NET 4 Caching Support

関連する問題