Объектный кэш для C#

Переменные не являются полиморфными в Java; они не переопределяют друг друга.

22
задан moogs 24 February 2009 в 11:18
поделиться

6 ответов

Я записал Кэш LRU и некоторые тестовые сценарии, не стесняйтесь использовать его.

можно прочитать источник на мой блог .

Для ленивого (здесь, это минус тестовые сценарии):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LRUCache {
    public class IndexedLinkedList<T> {

        LinkedList<T> data = new LinkedList<T>();
        Dictionary<T, LinkedListNode<T>> index = new Dictionary<T, LinkedListNode<T>>();

        public void Add(T value) {
            index[value] = data.AddLast(value);
        }

        public void RemoveFirst() {
            index.Remove(data.First.Value);
            data.RemoveFirst();
        }

        public void Remove(T value) {
            LinkedListNode<T> node;
            if (index.TryGetValue(value, out node)) {
                data.Remove(node);
                index.Remove(value);
            }
        }

        public int Count {
            get {
                return data.Count;
            }
        }

        public void Clear() {
            data.Clear();
            index.Clear();
        }

        public T First {
            get {
                return data.First.Value;
            }
        }
    }
}

LRUCache

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LRUCache {
    public class LRUCache<TKey, TValue> : IDictionary<TKey, TValue> {

        object sync = new object();
        Dictionary<TKey, TValue> data;
        IndexedLinkedList<TKey> lruList = new IndexedLinkedList<TKey>();
        ICollection<KeyValuePair<TKey, TValue>> dataAsCollection;
        int capacity;

        public LRUCache(int capacity) {

            if (capacity <= 0) {
                throw new ArgumentException("capacity should always be bigger than 0");
            }

            data = new Dictionary<TKey, TValue>(capacity);
            dataAsCollection = data;
            this.capacity = capacity;
        }

        public void Add(TKey key, TValue value) {
            if (!ContainsKey(key)) {
                this[key] = value;
            } else {
                throw new ArgumentException("An attempt was made to insert a duplicate key in the cache.");
            }
        }

        public bool ContainsKey(TKey key) {
            return data.ContainsKey(key);
        }

        public ICollection<TKey> Keys {
            get {
                return data.Keys;
            }
        }

        public bool Remove(TKey key) {
            bool existed = data.Remove(key);
            lruList.Remove(key);
            return existed;
        }

        public bool TryGetValue(TKey key, out TValue value) {
            return data.TryGetValue(key, out value);
        }

        public ICollection<TValue> Values {
            get { return data.Values; }
        }

        public TValue this[TKey key] {
            get {
                var value = data[key];
                lruList.Remove(key);
                lruList.Add(key);
                return value;
            }
            set {
                data[key] = value;
                lruList.Remove(key);
                lruList.Add(key);

                if (data.Count > capacity) {
                    data.Remove(lruList.First);
                    lruList.RemoveFirst();
                }
            }
        }

        public void Add(KeyValuePair<TKey, TValue> item) {
            Add(item.Key, item.Value);
        }

        public void Clear() {
            data.Clear();
            lruList.Clear();
        }

        public bool Contains(KeyValuePair<TKey, TValue> item) {
            return dataAsCollection.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
            dataAsCollection.CopyTo(array, arrayIndex);
        }

        public int Count {
            get { return data.Count; }
        }

        public bool IsReadOnly {
            get { return false; }
        }

        public bool Remove(KeyValuePair<TKey, TValue> item) {

            bool removed = dataAsCollection.Remove(item);
            if (removed) {
                lruList.Remove(item.Key);
            }
            return removed;
        }


        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
            return dataAsCollection.GetEnumerator();
        }


        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return ((System.Collections.IEnumerable)data).GetEnumerator();
        }

    }
}
21
ответ дан Sam Saffron 29 November 2019 в 04:00
поделиться

Существует шаблоны & Библиотека Предприятия методов (более конкретно, Блок Программы кэширования ), но это IMO имеет тенденцию быть сверхспроектированным и чрезмерно сложный.

8
ответ дан Anton Gogolev 29 November 2019 в 04:00
поделиться

Платформа.NET всегда имела способность сохранить слабые ссылки к объектам.

В основном, слабые ссылки являются ссылками на объекты, которые время выполнения считает "неважным", и это может быть удалено сборкой "мусора", выполненной в любом моменте времени. Это может использоваться, например, к вещам кэша, но Вы не имели бы никакого контроля над тем, что собрано и что нет.

, С другой стороны, это очень просто в использовании, и это может просто быть тем, в чем Вы нуждаетесь.

Dave

7
ответ дан Dave Van den Eynde 29 November 2019 в 04:00
поделиться

Классическая ситуация компромисса. Хранение всего в памяти будет быстро за счет в широком масштабе увеличенного потребления памяти, пока получение от диска уменьшает потребление памяти, но не так производительно. Однако Вы уже знаете все это!

встроенное Система. Сеть. Кэширование. Кэш класс является большим, и я использовал его успешно много раз сам в моих приложениях ASP.NET (хотя главным образом для записи базы данных, кэширующейся), однако, недостаток состоит в том, что кэш будет только работать на одной машине (обычно единственный веб-сервер) и не может быть распределен через несколько машин.

, Если возможно "бросить некоторые аппаратные средства" в проблему, и это должны не обязательно быть дорогие аппаратные средства, просто поля с большим количеством памяти, Вы могли всегда идти с решением для распределенного кэширования. Это даст Вам намного больше памяти для проигрывания с при сохранении (почти) того же уровня производительности.

опции Some для решения для распределенного кэширования для.NET:

Memcached.NET

indeXus. Сеть

или даже Microsoft, собственная Скорость проект.

4
ответ дан CraigTP 29 November 2019 в 04:00
поделиться

Как Вы реализуете свой кэш?

можно использовать Cache класс от System.Web.Caching , даже в невеб-приложениях, и он произведет чистку объектов на основе LRU, если/когда ему будет нужна память.

В невеб-приложении необходимо будет использовать HttpRuntime.Cache для доступа Cache экземпляр.

Примечание, что документация указывает, что Cache класс не предназначается, чтобы использоваться за пределами ASP.NET, хотя это всегда работало на меня. (Я никогда не полагался на него ни в каком важнейшем приложении все же.)

3
ответ дан LukeH 29 November 2019 в 04:00
поделиться

Блок программы кэширования и кэш ASP.NET являются оба опциями однако, хотя они делают LRU, единственный вид использования диска, которое происходит, подкачкой страниц памяти. Я думаю, что существуют способы, которыми можно оптимизировать это, которые более характерны для цели получить лучший вывод. Вот некоторые мысли:

  • , Так как это - приложение ASP.NET, почему бы не генерировать изображения, пишут им в диск, и когда браузер запрашивает, чтобы следующая страница имела IIS, подают его. Это сохраняет Ваш рабочий процесс ASP.NET ниже, позволяя IIS сделать то, к чему он способен.
  • статистика Использования о том, как взаимодействует пользователь. LRU, как реализовано в кэше ASP.NET будет обычно относиться к отдельным файлам изображений - не много использования для этого сценария звуками его. Вместо этого возможно, некоторая логика как: "Если пользователь прокрутил X страницы в прошлые секунды Y, то общий следующие изображения X*Y". Пользователи, прокручивающие быстро, получат больше сгенерированных страниц; пользователям, читающим медленно, будет нужно менее кэшируемый.
  • Имеют изображения подачи IIS от диска и используют пользовательский обработчик HTTP для изображений, из которых Вы действительно хотите управлять кэшированием.
  • Имеют браузер, запрашивают файлы заранее также и полагаются на кэширование браузера.
  • , После того как изображение было вручено клиенту, действительно ли справедливо сказать, что это может в значительной степени быть удалено из кэша? Это могло уменьшить место существенно.

я, конечно, избегал бы использования простой хеш-таблицы все же.

0
ответ дан Paul Stovell 29 November 2019 в 04:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: