Кеширование в C # /. Net

Я хотел спросить вас, каков наилучший подход для реализации кэша в C #? Есть ли возможность при использовании данных классов .NET или что-то в этом роде? Возможно, что-то вроде словаря, который удалит некоторые записи, если он станет слишком большим, но где чьи записи не будут удалены сборщиком мусора?

14.08.2009 07:50:44
Это сильно зависит от приложения. Для чего ты это используешь?
Sam Harwell 14.08.2009 07:56:49
не в asp.net, но я пока точно не знаю, я опубликую требования, когда получу их, но спасибо за ваш первый ответ :)
Sebastian Müller 14.08.2009 08:02:21
Надежное .NET Caching покрывает распространенные ошибки кэширования и предоставляет библиотеку, которая помогает разработчикам избежать некоторых распространенных ошибок. В посте конкретно объясняется, как вы можете безопасно использовать MemoryCache .
Steven Wexler 16.05.2014 03:09:00
Эту статью стоит прочитать: jondavis.net/techblog/post/2010/08/30/…
AFract 28.05.2014 09:49:49
10 ОТВЕТОВ
РЕШЕНИЕ

Если вы используете ASP.NET, вы можете использовать Cacheкласс ( System.Web.Caching).

Вот хороший вспомогательный класс: c-cache-helper-class

Если вы имеете в виду кэширование в приложении Windows Form, это зависит от того, что вы пытаетесь сделать, и где вы пытаетесь кэшировать данные.

Мы реализовали кеш позади Web-сервиса для определенных методов
(используя System.Web.Cachingобъект.).

Тем не менее, вы также можете посмотреть на блок приложения кэширования. ( См. Здесь), которая является частью Enterprise Library для .NET Framework 2.0.

17
22.03.2018 13:01:07
это не говорит, что он использует asp.net
Toad 14.08.2009 09:11:03
Я предложил вариант для asp.net, а также подход, когда вас нет. Блок приложения для кеширования.
Bravax 14.08.2009 09:16:56
Не имеет значения, если это asp.net или нет. Вы можете ссылаться на System.Web в настольном приложении и использовать System.Web.Cache через свойство HttpRuntime.Cache.
Ricardo Nolde 17.12.2009 14:46:22
@RicardoNolde, но это зависит от того, на какой профиль .net он ссылается. Если он использует приложение по умолчанию для приложения Windows (профиль клиента), пространство имен System.Web недоступно.
m__ 20.06.2013 07:13:18
MemoryCache доступен для тех, кто не использует ASP.NET, в более поздних версиях .NET.
jpaugh 28.09.2018 20:25:34

Вы можете использовать Hashtable

у него очень быстрый поиск, нет столкновений ключей, и ваши данные не будут собирать мусор

-2
14.08.2009 08:04:06
но что если хеш-таблицы станут слишком большими?
Sebastian Müller 14.08.2009 09:02:37
Единственное, что может случиться, это то, что у вас не хватает памяти. Если это не так, хеш-таблица работает нормально. Внутренне он исправляет ключевые столкновения, с которыми он может столкнуться, поэтому вы этого не заметите.
Toad 14.08.2009 09:09:57
Hashtable это не кеш, это поиск (если используется для этой цели). Кэш имеет срок действия, очистку, управление емкостью и иногда поддержку транзакций, замораживание и многие другие функции. Посмотрите на Кэширующий блок приложений, хотя он заставляет вас вносить целую ферму других блоков приложений и требует очень много конфигурации.
Khash 20.08.2009 09:33:28
Класс Hashtable теперь фактически мертв в .NET, используйте словарь ( stackoverflow.com/questions/301371/… )
bytedev 4.03.2016 12:09:11

Если вы хотите что-то кэшировать в ASP.Net, я бы посмотрел на класс Cache. Например

Hashtable menuTable = new Hashtable(); 
menuTable.add("Home","default.aspx"); 
Cache["menu"] = menuTable; 

Затем, чтобы получить его снова

Hashtable menuTable = (Hashtable)Cache["menu"];
-1
14.08.2009 08:13:33

Вы можете использовать ObjectCache.

См. Http://msdn.microsoft.com/en-us/library/system.runtime.caching.objectcache.aspx

2
30.08.2012 22:13:05

Если вы используете .NET 4 или выше, вы можете использовать класс MemoryCache .

28
28.09.2012 12:55:23

Классы кеша, поставляемые с .NET, удобны, но имеют большую проблему - они не могут хранить много данных (десятки миллионов +) объектов в течение длительного времени, не убивая ваш GC. Они отлично работают, если вы кешируете несколько тысяч объектов, но в тот момент, когда вы перемещаетесь в миллионы и сохраняете их, пока они не распространятся в GEN2 - паузы GC в конечном итоге начнут становиться заметными, когда ваша система достигнет низкого порога памяти и GC потребуется развернуть все гены.

Практичность заключается в следующем - если вам нужно хранить несколько сотен тысяч экземпляров - используйте кэш MS. Не имеет значения, являются ли ваши объекты 2-мя или 25-ю полями - речь идет о количестве ссылок.

С другой стороны, бывают случаи, когда необходимо использовать большие ОЗУ, которые в наши дни являются обычными, то есть 64 ГБ. Для этого мы создали 100% управляемый менеджер памяти и кеш, который находится поверх него.

Наше решение может легко хранить 300 000 000 объектов в оперативной памяти без какой-либо нагрузки на GC - это потому, что мы храним данные в больших (250 МБ) байт [] сегментах.

Вот код: NFX Pile (Apache 2.0)

И видео: NFX Pile Cache - Youtube

2
1.06.2015 22:47:06

Ваш вопрос нуждается в уточнении. C # это язык, а не рамки. Вы должны указать, какую платформу вы хотите реализовать кеширование. Если учесть, что вы хотите реализовать это в ASP.NET, это все еще полностью зависит от того, что вы хотите от Cache. Вы можете выбрать между кэшем в процессе (который будет хранить данные в куче вашего приложения) и кэшем вне процесса (в этом случае вы можете хранить данные в другой памяти, отличной от кучи, такой как сервер кэша Amazon Elastic). И есть еще одно решение - между кэшированием клиента или сторонним кэшированием. Обычно в решении вы должны разработать другое решение для кэширования разных данных. Потому что на основе четырех факторов (доступность, постоянство, размер, стоимость) вы должны решить, какое решение вам нужно.

0
27.04.2016 12:20:28

MemoryCache в этой среде - хорошее место для начала, но вы также можете рассмотреть библиотеку с открытым исходным кодом LazyCache, поскольку она имеет более простой API, чем кэш-память и имеет встроенную блокировку, а также некоторые другие удобные для разработчика функции. Это также доступно на nuget.

Чтобы дать вам пример:

// Create our cache service using the defaults (Dependency injection ready).
// Uses MemoryCache.Default as default so cache is shared between instances
IAppCache cache = new CachingService();

// Declare (but don't execute) a func/delegate whose result we want to cache
Func<ComplexObjects> complexObjectFactory = () => methodThatTakesTimeOrResources();

// Get our ComplexObjects from the cache, or build them in the factory func 
// and cache the results for next time under the given key
ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", complexObjectFactory);

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

(Отказ от ответственности: я автор LazyCache)

3
30.05.2016 14:43:08
Более простой API, чем MemoryCache? Мне трудно в это поверить, так как это, пожалуй, самый простой API, который Microsoft предлагает. Я также пытаюсь выяснить точную причину, почему вы создали совершенно новый API кеширования? Это выглядит прилично и почти все, но почему вы приложили все усилия для чего-то, что было вокруг и стабильно целую вечность.
hbulens 11.07.2016 19:21:50
Это не значительное изменение в кеше памяти, но оно решает проблему параллелизма и уменьшает дублирование с помощью однострочных откачиваемых делегатов. Написав один и тот же грубый код несколько раз, это экономит время для меня, имея библиотеку, и этого достаточно для меня.
alastairtree 16.07.2016 14:11:43

Для местных магазинов

1
5.09.2016 17:55:53

Я написал это некоторое время назад, и это, кажется, работает хорошо. Это позволяет дифференцировать различные магазины кэша с использованием различных типов: ApplicationCaching<MyCacheType1>, ApplicationCaching<MyCacheType2>....

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

Вам понадобится ссылка на Newtonsoft.Jsonсериализатор (или использовать альтернативный), и, конечно, все объекты или типы значений для кэширования должны быть сериализуемыми.

Используйте, MaxItemCountчтобы установить ограничение на количество товаров в любом магазине.

Используется отдельный класс Zipper (см. Код ниже) System.IO.Compression. Это минимизирует размер магазина и помогает ускорить время загрузки.


public static class ApplicationCaching<K> 
{
        //====================================================================================================================
        public static event EventHandler InitialAccess = (s, e) => { };
        //=============================================================================================
        static Dictionary<string, byte[]> _StoredValues;
        static Dictionary<string, DateTime> _ExpirationTimes = new Dictionary<string, DateTime>();
        //=============================================================================================
        public static int MaxItemCount { get; set; } = 0;
        private static void OnInitialAccess()
        {
            //-----------------------------------------------------------------------------------------
            _StoredValues = new Dictionary<string, byte[]>();
            //-----------------------------------------------------------------------------------------
            InitialAccess?.Invoke(null, EventArgs.Empty);
            //-----------------------------------------------------------------------------------------
        }
        public static void AddToCache<T>(string key, T value, DateTime expirationTime)
        {
            try
            {
                //-----------------------------------------------------------------------------------------
                if (_StoredValues is null) OnInitialAccess();
                //-----------------------------------------------------------------------------------------
                string strValue = JsonConvert.SerializeObject(value);
                byte[] zippedValue = Zipper.Zip(strValue);
                //-----------------------------------------------------------------------------------------
                _StoredValues.Remove(key);
                _StoredValues.Add(key, zippedValue);
                //-----------------------------------------------------------------------------------------
                _ExpirationTimes.Remove(key);
                _ExpirationTimes.Add(key, expirationTime);
                //-----------------------------------------------------------------------------------------
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }
        //=============================================================================================
        public static T GetFromCache<T>(string key, T defaultValue = default)
        {
            try
            {
                //-----------------------------------------------------------------------------------------
                if (_StoredValues is null) OnInitialAccess();
                //-----------------------------------------------------------------------------------------
                if (_StoredValues.ContainsKey(key))
                {
                    //------------------------------------------------------------------------------------------
                    if (_ExpirationTimes[key] <= DateTime.Now)
                    {
                        //------------------------------------------------------------------------------------------
                        _StoredValues.Remove(key);
                        _ExpirationTimes.Remove(key);
                        //------------------------------------------------------------------------------------------
                        return defaultValue;
                        //------------------------------------------------------------------------------------------
                    }
                    //------------------------------------------------------------------------------------------
                    byte[] zippedValue = _StoredValues[key];
                    //------------------------------------------------------------------------------------------
                    string strValue = Zipper.Unzip(zippedValue);
                    T value = JsonConvert.DeserializeObject<T>(strValue);
                    //------------------------------------------------------------------------------------------
                    return value;
                    //------------------------------------------------------------------------------------------
                }
                else
                {
                    return defaultValue;
                }
                //---------------------------------------------------------------------------------------------
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        //=============================================================================================
        public static string ConvertCacheToString()
        {
            //-----------------------------------------------------------------------------------------
            if (_StoredValues is null || _ExpirationTimes is null) return "";
            //-----------------------------------------------------------------------------------------
            List<string> storage = new List<string>();
            //-----------------------------------------------------------------------------------------
            string strStoredObject = JsonConvert.SerializeObject(_StoredValues);
            string strExpirationTimes = JsonConvert.SerializeObject(_ExpirationTimes);
            //-----------------------------------------------------------------------------------------
            storage.AddRange(new string[] { strStoredObject, strExpirationTimes});
            //-----------------------------------------------------------------------------------------
            string strStorage = JsonConvert.SerializeObject(storage);
            //-----------------------------------------------------------------------------------------
            return strStorage;
            //-----------------------------------------------------------------------------------------
        }
        //=============================================================================================
        public static void InializeCacheFromString(string strCache)
        {
            try
            {
                //-----------------------------------------------------------------------------------------
                List<string> storage = JsonConvert.DeserializeObject<List<string>>(strCache);
                //-----------------------------------------------------------------------------------------
                if (storage != null && storage.Count == 2)
                {
                    //-----------------------------------------------------------------------------------------
                    _StoredValues = JsonConvert.DeserializeObject<Dictionary<string, byte[]>>(storage.First());
                    _ExpirationTimes = JsonConvert.DeserializeObject<Dictionary<string, DateTime>>(storage.Last());
                    //-----------------------------------------------------------------------------------------
                    if (_ExpirationTimes != null && _StoredValues != null)
                    {
                        //-----------------------------------------------------------------------------------------
                        for (int i = 0; i < _ExpirationTimes.Count; i++)
                        {
                            string key = _ExpirationTimes.ElementAt(i).Key;
                            //-----------------------------------------------------------------------------------------
                            if (_ExpirationTimes[key] < DateTime.Now)
                            {
                                ClearItem(key);
                            }
                            //-----------------------------------------------------------------------------------------
                        }

                        //-----------------------------------------------------------------------------------------
                        if (MaxItemCount > 0 && _StoredValues.Count > MaxItemCount)
                        {
                            IEnumerable<KeyValuePair<string, DateTime>> countedOutItems = _ExpirationTimes.OrderByDescending(o => o.Value).Skip(MaxItemCount);
                            for (int i = 0; i < countedOutItems.Count(); i++)
                            {
                                ClearItem(countedOutItems.ElementAt(i).Key);
                            }
                        }
                        //-----------------------------------------------------------------------------------------
                        return;
                        //-----------------------------------------------------------------------------------------
                    }
                    //-----------------------------------------------------------------------------------------
                }
                //-----------------------------------------------------------------------------------------
                _StoredValues = new Dictionary<string, byte[]>();
                _ExpirationTimes = new Dictionary<string, DateTime>();
                //-----------------------------------------------------------------------------------------
            }
            catch (Exception)
            {
                throw;
            }
        }
        //=============================================================================================
        public static void ClearItem(string key)
        {
            //-----------------------------------------------------------------------------------------
            if (_StoredValues.ContainsKey(key))
            {
                _StoredValues.Remove(key);
            }
            //-----------------------------------------------------------------------------------------
            if (_ExpirationTimes.ContainsKey(key))
                _ExpirationTimes.Remove(key);
            //-----------------------------------------------------------------------------------------
        }
        //=============================================================================================
    }

Вы можете легко начать использовать кеш на лету с чем-то вроде ...

            //------------------------------------------------------------------------------------------------------------------------------
            string key = "MyUniqueKeyForThisItem";
            //------------------------------------------------------------------------------------------------------------------------------
            MyType obj = ApplicationCaching<MyCacheType>.GetFromCache<MyType>(key);
            //------------------------------------------------------------------------------------------------------------------------------

            if (obj == default)
            {
                obj = new MyType(...);
                ApplicationCaching<MyCacheType>.AddToCache(key, obj, DateTime.Now.AddHours(1));
            }

Обратите внимание, что фактические типы, хранящиеся в кэше, могут быть одинаковыми или отличаться от типа кэша. Тип кэша используется ТОЛЬКО для различения разных хранилищ кэша.

Затем вы можете разрешить сохранение кэша после завершения выполнения, используя Default Settings

string bulkCache = ApplicationCaching<MyType>.ConvertCacheToString();
                //--------------------------------------------------------------------------------------------------------
                if (bulkCache != "")
                {
                    Properties.Settings.Default.*MyType*DataCachingStore = bulkCache;
                }
                //--------------------------------------------------------------------------------------------------------
                try
                {
                    Properties.Settings.Default.Save();
                }
                catch (IsolatedStorageException)
                {
                    //handle Isolated Storage exceptions here
                }

Обработайте событие InitialAccess, чтобы повторно инициализировать кэш при перезапуске приложения.

private static void ApplicationCaching_InitialAccess(object sender, EventArgs e)
        {
            //-----------------------------------------------------------------------------------------
            string storedCache = Properties.Settings.Default.*MyType*DataCachingStore;
            ApplicationCaching<MyCacheType>.InializeCacheFromString(storedCache);
            //-----------------------------------------------------------------------------------------
        }

Наконец, вот класс Zipper ...

public class Zipper
    {
        public static void CopyTo(Stream src, Stream dest)
        {
            byte[] bytes = new byte[4096];

            int cnt;

            while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
            {
                dest.Write(bytes, 0, cnt);
            }
        }

        public static byte[] Zip(string str)
        {
            var bytes = Encoding.UTF8.GetBytes(str);

            using (var msi = new MemoryStream(bytes))
            using (var mso = new MemoryStream())
            {
                using (var gs = new GZipStream(mso, CompressionMode.Compress))
                {
                    CopyTo(msi, gs);
                }
                return mso.ToArray();
            }
        }

        public static string Unzip(byte[] bytes)
        {
            using (var msi = new MemoryStream(bytes))
            using (var mso = new MemoryStream())
            {
                using (var gs = new GZipStream(msi, CompressionMode.Decompress))
                {
                    CopyTo(gs, mso);
                }
                return Encoding.UTF8.GetString(mso.ToArray());
            }
        }
    }
0
30.11.2019 10:02:36