手始めに、以下のコードがスレッドセーフではないことを知っていることをそこに投げさせてください(修正:そうかもしれません)。私が苦労しているのは、実際にテストで失敗する可能性のある実装を見つけることです。現在、大規模な WCF プロジェクトをリファクタリングしています。このプロジェクトでは、(ほとんどの場合) 静的データをキャッシュし、SQL データベースからデータを取り込む必要があります。少なくとも 1 日に 1 回は有効期限が切れて「更新」される必要があるため、MemoryCache を使用しています。
以下のコードはスレッドセーフであってはならないことは知っていますが、負荷が高い場合に失敗することはありません。複雑なことに、Google検索では実装が両方の方法で表示されます(ロックの有無にかかわらず、それらが必要かどうかの議論と組み合わされています.
マルチスレッド環境での MemoryCache の知識を持っている人が、remove の呼び出し (めったに呼び出されることはありませんが、その要件です) が取得/再作成中にスローされないように、適切な場所でロックする必要があるかどうかを明確に知ることができますか?
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;
}
}