Подтвердить что ты не робот

Как реализовать общий менеджер кэша в С#

Я пытаюсь реализовать общий диспетчер кэша, но я не уверен, как это сделать.

У меня есть следующее до сих пор, однако, если у меня есть две записи кэша с одинаковыми типами возвращаемых данных, то я предполагаю, что тот же объект блокировки будет использоваться!

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;
    }
}

Любая помощь будет очень признательна!

4b9b3361

Ответ 1

Вы правы, это будет использовать ту же самую блокировку для всех записей кэша одного и того же типа. Чтобы сохранить фактический метод кэширования (память, файл, база данных...), независимый от этого диспетчера кэша, я предлагаю хранить дополнительный объект синхронизации для каждой записи в кэш, поэтому ваши записи кэша будут выглядеть, например, как Tuple<object, TResult>, а не просто TResult, где object будет new object() для каждой записи и будет использоваться для блокировки.

Ответ 2

Вы никогда не должны блокировать свой код кеширования, если он действительно не нужен. Используйте параллельный словарь, если вы не хотите использовать какой-либо известный кэш.

Я бы также сказал, что вы, вероятно, должны использовать System.Runtime.MemorCache.

Или вы используете решение, которое абстрактно для вас, как мой CacheManager https://github.com/MichaCo/CacheManager;)

Ответ 3

Я не уверен, что вы должны использовать lock, alos, почему бы не использовать MemoryCache вместо интерфейса ICache? Разве недостаточно общего кеша памяти? Почему вы заставили время кеша быть в считанные минуты, вы должны передать временные интервалы в свои методы кэширования, я был бы более общим.

Я реализовал версию диспетчера кэша несколько месяцев назад, но был веб-ориентирован.