問題:オブジェクトキャッシュを実装する必要があります。キャッシュはスレッドセーフで、オンデマンドで値を入力する必要があります(遅延読み込み)。値はキーによってWebサービス経由で取得されます(操作が遅い)。そのため、操作がアトミックで同期されていると想定して、ConcurrentDictionary
およびその GetOrAdd() メソッドを使用することにしました。残念ながら、MSDN記事で次のステートメントを見つけました: 方法:ConcurrentDictionaryからアイテムを追加および削除する :
また、ConcurrentDictionaryのすべてのメソッドはスレッドセーフですが、すべてのメソッドがアトミックではありません。具体的には、GetOrAddおよびAddOrUpdateです。これらのメソッドに渡されるユーザーデリゲートは、辞書の内部ロックの外部で呼び出されます。
まあそれは残念ですが、それでも私の答えに完全には答えません。
質問:値ファクトリはキーごとに1回だけ呼び出されますか?私の特定のケースでは、同じ値を求めるWebサービスへの複数の要求を生成する同じキーを探している複数のスレッドが可能ですか?
バリューファクトリはキーごとに1回だけ呼び出されますか?
いいえ、そうではありません。 ドキュメントによると :
異なるスレッドで
GetOrAdd
を同時に呼び出すと、valueFactoryが複数回呼び出されることがありますが、キーと値のペアは呼び出されない場合があります呼び出しごとに辞書に追加されます。
GetOrAdd
のソースコード を見てみましょう:
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
if (key == null) throw new ArgumentNullException("key");
if (valueFactory == null) throw new ArgumentNullException("valueFactory");
TValue resultingValue;
if (TryGetValue(key, out resultingValue))
{
return resultingValue;
}
TryAddInternal(key, valueFactory(key), false, true, out resultingValue);
return resultingValue;
}
残念ながら、この場合、2つのvalueFactory
呼び出しがたまたま並行して実行されても、GetOrAdd
が2回以上呼び出されないという保証は何もありません。