Я использую Cache
в методе веб-сервиса как это:
var pblDataList = (List<blabla>)HttpContext.Current.Cache.Get("pblDataList");
if (pblDataList == null)
{
var PBLData = dc.ExecuteQuery<blabla>(@"SELECT blabla");
pblDataList = PBLData.ToList();
HttpContext.Current.Cache.Add("pblDataList", pblDataList, null,
DateTime.Now.Add(new TimeSpan(0, 0, 15)),
Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}
Но интересно, действительно ли этот код ориентирован на многопотоковое исполнение? Метод веб-сервиса называют несколько запрашивающих сторон. И более затем одна запрашивающая сторона может попытаться получить данные и добавить к Cache
одновременно, в то время как кэш пуст.
Запрос занимает 5 - 8 секунд. Был бы, представляя оператор блокировки вокруг этого кода, предотвращают какие-либо возможные конфликты? (Я знаю, что несколько запросов могут работать одновременно, но я хочу быть уверенным, что только один запрос работает за один раз.)
Объект кэша является потокобезопасным , но HttpContext.Current
не будет доступен из фоновых потоков. Это может относиться или не относиться к вам здесь, из вашего фрагмента кода не очевидно, используете ли вы на самом деле фоновые потоки, но в случае, если вы используете сейчас или решите использовать это в какой-то момент в будущем, вам следует сохранить это в уме.
Если есть вероятность, что вам понадобится доступ к кешу из фонового потока, используйте вместо него HttpRuntime.Cache .
Кроме того, хотя отдельные операции с кешем являются потокобезопасными, последовательные операции поиска / сохранения, очевидно, не являются атомарными. Нужны ли вам , чтобы они были атомарными, зависит от вашего конкретного приложения. Если один и тот же запрос может быть выполнен несколько раз серьезной проблемой, то есть если он будет создавать большую нагрузку, чем может обработать ваша база данных, или если это будет проблемой для запроса на возврат данных, которые немедленно перезаписываются в cache, то вы, вероятно, захотите установить блокировку вокруг всего блока кода.
Однако в большинстве случаев вам действительно нужно сначала профилировать и посмотреть, действительно ли это проблема. Большинство веб-приложений / сервисов не заботятся об этом аспекте кеширования, потому что они не имеют состояния, и не имеет значения, будет ли кеш перезаписан.
Я считаю, что Add
должно быть поточно-ориентированным, то есть при вызове Add
ошибки не будет дважды с одним и тем же ключом, но очевидно, что запрос может выполнить дважды.
Другой вопрос, однако, - это потокобезопасность данных . Нет никакой гарантии, что каждый List
изолирован - это зависит от кеш-провайдера. Поставщик кэша в памяти хранит объекты напрямую, поэтому существует риск коллизий, если какой-либо из потоков редактирует данные (добавляет / удаляет / меняет местами элементы в списке или изменяет свойства одного из элементов). Однако с поставщиком сериализации все будет в порядке. Конечно, это требует, чтобы blabla
была сериализуемой ...
Вы правы. Операции извлечения и добавления не рассматриваются как атомарная транзакция. Если вам нужно предотвратить многократное выполнение запроса, вам нужно будет использовать блокировку.
(Обычно это не составляет большой проблемы, но в случае длительного запроса это может быть полезно для уменьшения нагрузки на базу данных.)