Как реализовать общий менеджер кэша в С#
Я пытаюсь реализовать общий диспетчер кэша, но я не уверен, как это сделать.
У меня есть следующее до сих пор, однако, если у меня есть две записи кэша с одинаковыми типами возвращаемых данных, то я предполагаю, что тот же объект блокировки будет использоваться!
public class CacheManager : ICacheManager
{
static class TypeLock<T>
{
public static readonly object SyncLock = new object();
}
private readonly ICache _cache;
public CacheManager(ICache cache)
{
if (cache == null)
throw new ArgumentNullException("cache");
_cache = cache;
}
public TResult AddCache<TResult>(string cacheKey, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
{
return AddCache(cacheKey, null, acquire, cacheDurationInMinutes);
}
public TResult AddCache<TResult>(string cacheKey, CacheDependency dependency, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
{
var entry = acquire.Invoke();
if (entry != null)
{
if (dependency != null)
_cache.InsertWithDependency(cacheKey, entry, dependency, DateTime.Now.AddMinutes(cacheDurationInMinutes));
else
_cache.Insert(cacheKey, entry, DateTime.Now.AddMinutes(cacheDurationInMinutes));
}
return entry;
}
public TResult GetOrAddCache<TResult>(string cacheKey, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
{
return GetOrAddCache(cacheKey, null, acquire, cacheDurationInMinutes);
}
public TResult GetOrAddCache<TResult>(string cacheKey, CacheDependency dependency, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
{
var entry = _cache.GetItem(cacheKey) as TResult;
if (entry == null)
{
lock (TypeLock<TResult>.SyncLock)
{
entry = _cache.GetItem(cacheKey) as TResult;
if (entry == null)
{
entry = acquire.Invoke();
if (entry != null)
{
if (dependency != null)
_cache.InsertWithDependency(cacheKey, entry, dependency,
DateTime.Now.AddMinutes(cacheDurationInMinutes));
else
_cache.Insert(cacheKey, entry, DateTime.Now.AddMinutes(cacheDurationInMinutes));
}
}
}
}
return entry;
}
}
Любая помощь будет очень признательна!
Ответы
Ответ 1
Вы правы, это будет использовать ту же самую блокировку для всех записей кэша одного и того же типа. Чтобы сохранить фактический метод кэширования (память, файл, база данных...), независимый от этого диспетчера кэша, я предлагаю хранить дополнительный объект синхронизации для каждой записи в кэш, поэтому ваши записи кэша будут выглядеть, например, как Tuple<object, TResult>
, а не просто TResult
, где object
будет new object()
для каждой записи и будет использоваться для блокировки.
Ответ 2
Вы никогда не должны блокировать свой код кеширования, если он действительно не нужен.
Используйте параллельный словарь, если вы не хотите использовать какой-либо известный кэш.
Я бы также сказал, что вы, вероятно, должны использовать System.Runtime.MemorCache
.
Или вы используете решение, которое абстрактно для вас,
как мой CacheManager https://github.com/MichaCo/CacheManager;)
Ответ 3
Я не уверен, что вы должны использовать lock, alos, почему бы не использовать MemoryCache вместо интерфейса ICache? Разве недостаточно общего кеша памяти?
Почему вы заставили время кеша быть в считанные минуты, вы должны передать временные интервалы в свои методы кэширования, я был бы более общим.
Я реализовал версию диспетчера кэша несколько месяцев назад, но был веб-ориентирован.