ここでは、スタックオーバーフローの私は、単一の引数関数をmemoizes foundコードをしました:メモ化機能は、同時に複数のスレッドから呼び出されたときスレッドセーフな関数のメモをC#でどのように実行するのですか?
static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
var d = new Dictionary<A, R>();
return a=>
{
R r;
if (!d.TryGetValue(a, out r))
{
r = f(a);
d.Add(a, r);
}
return r;
};
}
このコードは私のためにその仕事をしていませんが、それは時々失敗します。 Add
メソッドは同じ引数で2回呼び出され、例外がスローされます。
どのようにしてメモをスレッドセーフにすることができますか?それは同時に複数のスレッドから呼び出すことができますので、f
はスレッドセーフそのものである必要があり
static Func<A, R> ThreadsafeMemoize<A, R>(this Func<A, R> f)
{
var cache = new ConcurrentDictionary<A, R>();
return argument => cache.GetOrAdd(argument, f);
}
機能:
'GetOrAdd'は、指定された引数に対してfが複数回呼び出されることを完全に防止しないことに注意してください。呼び出しのちょうど* 1 *の結果が辞書に追加されることを保証します。キャッシュされた値が追加される前に、スレッドが同時にキャッシュをチェックするイベントでは、複数の呼び出しを取得できます。このことについて気にすることはしばしばありませんが、呼び出しに望ましくない副作用がある場合には、それについて言及します。 –
@JamesWorldはい、そうです。それを反映するように編集された答えは、ありがとう! – Gman
私はちょっと混乱しています - ローカル変数の 'cache'はここにありませんか? 'ThreadsafeMemoize()'が呼び出されるたびに、新しい辞書は作成されませんか? – dashnick