MemoryCache スレッドセーフティ、ロックは必要ですか? 質問する

MemoryCache スレッドセーフティ、ロックは必要ですか? 質問する

まず、以下のコードはスレッド セーフではない (訂正: おそらくそう) ことはわかっています。私が苦労しているのは、スレッド セーフな実装と、実際にテストで失敗させることができる実装を見つけることです。現在、大規模な WCF プロジェクトをリファクタリングしていますが、このプロジェクトでは、一部の (主に) 静的データをキャッシュし、SQL データベースから取り込む必要があります。少なくとも 1 日に 1 回は期限切れにして「更新」する必要があるため、MemoryCache を使用しています。

以下のコードはスレッドセーフではないことはわかっていますが、高負荷時に失敗させることはできず、さらに問題を複雑にしているのは、Google 検索で両方の実装方法 (ロックありとロックなし) と、ロックが必要かどうかの議論が示されることです。

マルチスレッド環境での MemoryCache の知識がある方は、削除の呼び出し (めったに呼び出されませんが、必須です) が取得/再作成中にスローされないように、適切な場所でロックする必要があるかどうかを明確に教えてください。

public class MemoryCacheService : IMemoryCacheService
{
    private const string PunctuationMapCacheKey = "punctuationMaps";
    private static readonly ObjectCache Cache;
    private readonly IAdoNet _adoNet;

    static MemoryCacheService()
    {
        Cache = MemoryCache.Default;
    }

    public MemoryCacheService(IAdoNet adoNet)
    {
        _adoNet = adoNet;
    }

    public void ClearPunctuationMaps()
    {
        Cache.Remove(PunctuationMapCacheKey);
    }

    public IEnumerable GetPunctuationMaps()
    {
        if (Cache.Contains(PunctuationMapCacheKey))
        {
            return (IEnumerable) Cache.Get(PunctuationMapCacheKey);
        }

        var punctuationMaps = GetPunctuationMappings();

        if (punctuationMaps == null)
        {
            throw new ApplicationException("Unable to retrieve punctuation mappings from the database.");
        }

        if (punctuationMaps.Cast<IPunctuationMapDto>().Any(p => p.UntaggedValue == null || p.TaggedValue == null))
        {
            throw new ApplicationException("Null values detected in Untagged or Tagged punctuation mappings.");
        }

        // Store data in the cache
        var cacheItemPolicy = new CacheItemPolicy
        {
            AbsoluteExpiration = DateTime.Now.AddDays(1.0)
        };

        Cache.AddOrGetExisting(PunctuationMapCacheKey, punctuationMaps, cacheItemPolicy);

        return punctuationMaps;
    }

    //Go oldschool ADO.NET to break the dependency on the entity framework and need to inject the database handler to populate cache
    private IEnumerable GetPunctuationMappings()
    {
        var table = _adoNet.ExecuteSelectCommand("SELECT [id], [TaggedValue],[UntaggedValue] FROM [dbo].[PunctuationMapper]", CommandType.Text);
        if (table != null && table.Rows.Count != 0)
        {
            return AutoMapper.Mapper.DynamicMap<IDataReader, IEnumerable<PunctuationMapDto>>(table.CreateDataReader());
        }

        return null;
    }
}

ベストアンサー1

MS が提供するデフォルトのMemoryCacheものは完全にスレッド セーフです。 から派生したカスタム実装はMemoryCacheスレッド セーフではない可能性があります。MemoryCacheそのままのプレーンなものを使用している場合は、スレッド セーフです。 オープン ソースの分散キャッシュ ソリューションのソース コードを参照して、私がどのように使用しているかを確認してください (MemCache.cs):

https://github.com/haneytron/dache/blob/master/Dache.CacheHost/Storage/MemCache.cs

おすすめ記事