Добрый день Здесь нужно было сделать очень примитивный кэш, чтобы не пришлось лишний раз заходить в базу данных.
При этом данные в базе статичны, и вопрос не столько в обновлении данных, сколько в том, когда их выкинуть, чтобы не занимать память, а удобство использования конечно важно.
Сначала я хотел использовать MemoryCache, но он мне показался слишком запутанным, да ещё и без строгой типизации.
Пример реализации см.
в кат.
Выполнение
Общая идея такова: кэш должен быть удобным и прозрачным в использовании.Меня вдохновил интерфейс класса ThreadLocal. Поэтому конструктору требуется фабричный метод для получения начальных значений, а затем они кэшируются.
Опять же, в моем случае я посчитал вполне логичным хранить данные по слабым ссылкам (WeakReference), чтобы до тех пор, пока данные нужны, кто-то ими пользуется, они будут доступны.
Далее по мере выделения новой памяти данные из кэша будут вытеснены.
Методов всего два: индексатор, который будет возвращать данные либо из источника, либо из кэша.
А также метод CleanCache для очистки словаря от мертвых ссылок и тем самым устранения утечек памяти.
В реальных условиях это не всегда необходимо.
Например, в моих условиях новые записи в кеше будут появляться всего несколько раз в день, поэтому даже за годы работы ссылки не будут потреблять сколько-нибудь существенное количество памяти.
Цель публикации
В принципе, мне интересно услышать мнения о моей реализации, как бы вы это сделали и есть ли ошибки.
Ну, если кому-то поможет, берите и пользуйтесь :)
Источник
Теги: #C++ #кэш #.public class WeakCache<TKey,TValue> where TValue : class { const int cacheCleanInterval = 60; private readonly Func<TKey, TValue> getter; private readonly Dictionary<TKey, WeakReference> data = new Dictionary<TKey, WeakReference>(); private readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(); private DateTime lastCacheClean = DateTime.MinValue; public WeakCache(Func<TKey,TValue> getter) { this.getter = getter; } public TValue this[TKey key] { get { CleanCache(); try { rwLock.EnterUpgradeableReadLock(); WeakReference wr; TValue val; if (data.TryGetValue(key, out wr)) { val = (TValue)wr.Target; if (val != null) return val; } try { rwLock.EnterWriteLock(); if (data.TryGetValue(key, out wr)) { val = (TValue)wr.Target; if (val != null) return val; } data[key] = new WeakReference(val = getter(key)); return val; } finally { rwLock.ExitWriteLock(); } } finally { rwLock.ExitUpgradeableReadLock(); } } } void CleanCache() { if ((DateTime.Now - lastCacheClean).
TotalSeconds > cacheCleanInterval) { try { rwLock.EnterWriteLock(); if ((DateTime.Now - lastCacheClean).
TotalSeconds > cacheCleanInterval) { lastCacheClean = DateTime.Now; var refs = data.ToArray(); foreach (var weakReference in refs) { if (!weakReference.Value.IsAlive) data.Remove(weakReference.Key); } } } finally { rwLock.ExitWriteLock(); } } } }
NET #C++
-
5 Способов Уничтожить Ваш Компьютер
19 Oct, 24 -
Один Человек, Одна Миссия
19 Oct, 24 -
Монстры, Чудеса И Рождение Науки
19 Oct, 24 -
Третья Волна Вычислительной Гидродинамики
19 Oct, 24 -
Mail.ru Обогнал Rambler По Рентабельности
19 Oct, 24