C# での MemoryCache のクリアに関する質問と回答を読みました。次のような多くの推奨事項がありました:1.キャッシュを列挙し、すべてのアイテムを削除します-他の人によると、これは良くありません.列挙子を取得すると全体がロックされ、ドキュメントの一部から引用すると、あらゆる種類の黙示録が発生します. 、見つかりませんでした。警告が表示され、再現できませんでした。とにかく、これは非常に効率的な解決策だとは思いません。
キーを別のコレクションに保存し、それを繰り返して、キャッシュからアイテムを削除します。- これを除けば、あまりスレッド セーフとは言えません。効率的とも言えません。
古いキャッシュを破棄し、新しいキャッシュを作成する - これは良いことのように思えますが、古いキャッシュへの既存の参照が問題を引き起こす可能性があるという明らかな問題が頭に浮かび、いくつかのコメントで指摘されています。もちろん、アクションの順序は重要です。古いものの参照を保存し、古いものの代わりに新しいものを作成し、古いものを破棄する必要があります-誰もがこの小さなニュアンスに気付いていないようです.
ならどうしよう?私の同僚の 1 人が、私の問題に MemoryCache を使用することを提案しました。彼はキャッシュ オブジェクトを別のクラスにラップしました。このクラスには、キーを取得する (必要に応じてデータベースからロードする)、キーを削除する、またはキャッシュをクリアするオプションがあります。 . 最初の 2 つは今のところ重要ではありませんが、3 番目は興味深いものです。これには、「自分の実装以外の MemoryCache オブジェクトへの追加の参照がないことが保証されている」という行に沿って、3 番目のソリューションを使用しました。したがって、関連するコードは次のとおりです。
コンストラクタ:
public MyCache()
{
_cache = new MemoryCache("MyCache");
}
キャッシュの消去:
public void ClearCacheForAllUsers()
{
var oldCache = _cache;
_cache = new MemoryCache("MyCache");
oldCache.Dispose();
}
_cache はプライベートな MemoryCache オブジェクトです。
これにより、マルチスレッド環境で問題が発生する可能性はありますか? read と dispose を並行して呼び出すことに懸念があります。同時読み取りを許可する何らかのロック メカニズムを実装する必要がありますが、キャッシュのクリア関数は現在の読み取りがキャッシュで終了するまで待機しますか?
はい、これを実装する必要がありますが、それに到達する前にいくつかの洞察を得たいと思います。
ロバート
Vooの答えのEDIT 1: 「ラッパー」(MyCache)の外にいる人は誰も_cacheオブジェクトへの参照を取得しないことが保証されています。私の心配は次のようなものです。
T1:
MyCache.ClearAll()
var oldCache = _cache
T2:
MyCache.GetOrReadFromDb("stuff")
T1:
_cache=new MemoryCache("MyCache")
oldCache.Dispose()
T2:
*something bad*
古いキャッシュをまだ使用しているT2スレッドは別として、これは好ましくありませんが、私が住むことができるものは、Getメソッドが破棄された状態で古いキャッシュに何らかの形でアクセスしたり、データなしで新しいキャッシュを読み取ったりする状況がある可能性があります?
次のような GetOrReadFromDb 関数を想像してください。
public object GetOrReadFromDb(string key)
{
if(_cache[key]==null)
{
//Read stuff from DB, and insert into the cache
}
return _cache[key];
}
たとえば、db からの読み取り直後、および _chache[key] 値で戻る前に、読み取りスレッドから制御が奪われ、クリアに渡される可能性があり、それが問題を引き起こす可能性があると思います。それは本当の問題ですか?