Безопасность потоков MemoryCache: необходима ли блокировка? ⇐ C#
-
Гость
Безопасность потоков MemoryCache: необходима ли блокировка?
Для начала позвольте мне сказать, что я знаю, что приведенный ниже код не является потокобезопасным (исправление: может быть). С чем я борюсь, так это с поиском реализации, которая действительно может провалиться при тестировании. Сейчас я занимаюсь рефакторингом большого проекта WCF, для которого требуются некоторые (в основном) кэшированные статические данные и их заполнение из базы данных SQL. Он должен истечь и «обновиться» хотя бы раз в день, поэтому я использую MemoryCache.
Я знаю, что приведенный ниже код не должен быть потокобезопасным, но я не могу заставить его выходить из строя при большой нагрузке, и, что усложняет ситуацию, поиск в Google показывает реализации в обоих направлениях (с блокировками и без них в сочетании с дебатами о том, необходимы они или нет.
Может ли кто-нибудь со знанием MemoryCache в многопоточной среде сообщить мне, нужно ли мне блокировать там, где это необходимо, чтобы вызов удаления (который будет вызываться редко, но это обязательное требование) не выдавался во время извлечения/ повторное заселение.
публичный класс MemoryCacheService: IMemoryCacheService { частная константная строка PunctuationMapCacheKey = "punctuationMaps"; частный статический кэш ObjectCache только для чтения; частный IadoNet только для чтения _adoNet; статический MemoryCacheService() { Кэш = MemoryCache.Default; } общедоступная служба MemoryCacheService (IAdoNet adoNet) { _adoNet = adoNet; } общественная пустота ClearPunctuationMaps() { Cache.Remove(PunctuationMapCacheKey); } общедоступный IEnumerable GetPunctuationMaps() { если (Cache.Contains(PunctuationMapCacheKey)) { return (IEnumerable) Cache.Get(PunctuationMapCacheKey); } вар punctuationMaps = GetPunctuationMappings(); если (пунктуационные карты == ноль) { throw new ApplicationException("Невозможно получить сопоставления пунктуации из базы данных."); } if (punctuationMaps.Cast().Any(p => p.UntaggedValue == null || p.TaggedValue == null)) { throw new ApplicationException("В сопоставлениях пунктуации без тегов или с тегами обнаружены нулевые значения."); } // Сохраняем данные в кеше var cacheItemPolicy = новая CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddDays(1.0) }; Cache.AddOrGetExisting(PunctuationMapCacheKey, punctuationMaps,cacheItemPolicy); вернуть пунктуационные карты; } //Перейдите к старой школе ADO.NET, чтобы разорвать зависимость от инфраструктуры сущностей и необходимо внедрить обработчик базы данных для заполнения кеша частный IEnumerable GetPunctuationMappings() { var table = _adoNet.ExecuteSelectCommand("SELECT [id], [TaggedValue],[UntaggedValue] FROM [dbo].[PunctuationMapper]", CommandType.Text); if (таблица != null && table.Rows.Count != 0) { return AutoMapper.Mapper.DynamicMap(table.CreateDataReader()); } вернуть ноль; } }
Для начала позвольте мне сказать, что я знаю, что приведенный ниже код не является потокобезопасным (исправление: может быть). С чем я борюсь, так это с поиском реализации, которая действительно может провалиться при тестировании. Сейчас я занимаюсь рефакторингом большого проекта WCF, для которого требуются некоторые (в основном) кэшированные статические данные и их заполнение из базы данных SQL. Он должен истечь и «обновиться» хотя бы раз в день, поэтому я использую MemoryCache.
Я знаю, что приведенный ниже код не должен быть потокобезопасным, но я не могу заставить его выходить из строя при большой нагрузке, и, что усложняет ситуацию, поиск в Google показывает реализации в обоих направлениях (с блокировками и без них в сочетании с дебатами о том, необходимы они или нет.
Может ли кто-нибудь со знанием MemoryCache в многопоточной среде сообщить мне, нужно ли мне блокировать там, где это необходимо, чтобы вызов удаления (который будет вызываться редко, но это обязательное требование) не выдавался во время извлечения/ повторное заселение.
публичный класс MemoryCacheService: IMemoryCacheService { частная константная строка PunctuationMapCacheKey = "punctuationMaps"; частный статический кэш ObjectCache только для чтения; частный IadoNet только для чтения _adoNet; статический MemoryCacheService() { Кэш = MemoryCache.Default; } общедоступная служба MemoryCacheService (IAdoNet adoNet) { _adoNet = adoNet; } общественная пустота ClearPunctuationMaps() { Cache.Remove(PunctuationMapCacheKey); } общедоступный IEnumerable GetPunctuationMaps() { если (Cache.Contains(PunctuationMapCacheKey)) { return (IEnumerable) Cache.Get(PunctuationMapCacheKey); } вар punctuationMaps = GetPunctuationMappings(); если (пунктуационные карты == ноль) { throw new ApplicationException("Невозможно получить сопоставления пунктуации из базы данных."); } if (punctuationMaps.Cast().Any(p => p.UntaggedValue == null || p.TaggedValue == null)) { throw new ApplicationException("В сопоставлениях пунктуации без тегов или с тегами обнаружены нулевые значения."); } // Сохраняем данные в кеше var cacheItemPolicy = новая CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddDays(1.0) }; Cache.AddOrGetExisting(PunctuationMapCacheKey, punctuationMaps,cacheItemPolicy); вернуть пунктуационные карты; } //Перейдите к старой школе ADO.NET, чтобы разорвать зависимость от инфраструктуры сущностей и необходимо внедрить обработчик базы данных для заполнения кеша частный IEnumerable GetPunctuationMappings() { var table = _adoNet.ExecuteSelectCommand("SELECT [id], [TaggedValue],[UntaggedValue] FROM [dbo].[PunctuationMapper]", CommandType.Text); if (таблица != null && table.Rows.Count != 0) { return AutoMapper.Mapper.DynamicMap(table.CreateDataReader()); } вернуть ноль; } }
Мобильная версия