Безопасное использование HttpContext.Current.Cache - PullRequest
14 голосов
/ 14 апреля 2010

Я использую 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 секунд. Может ли введение оператора блокировки вокруг этого кода предотвратить возможные конфликты? (Я знаю, что несколько запросов могут выполняться одновременно, но я хочу быть уверен, что одновременно выполняется только один запрос.)

Ответы [ 3 ]

22 голосов
/ 14 апреля 2010

Объект кэша является поточно-ориентированным , но HttpContext.Current не будет доступен из фоновых потоков. Это может относиться к вам, а может и не применяться, из вашего фрагмента кода не очевидно, являетесь ли вы пользователем на самом деле используя фоновые потоки, но если вы сейчас или решите в какой-то момент в будущем, вы должны помнить об этом.

Если есть вероятность, что вам понадобится получить доступ к кешу из фонового потока, используйте вместо этого HttpRuntime.Cache .

Кроме того, хотя отдельные операции с кешем являются поточно-ориентированными, последовательные операции поиска / сохранения, очевидно, не являются атомарными. Нужно ли вам , чтобы они были атомарными, зависит от вашего конкретного применения. Если это может быть серьезной проблемой для выполнения одного и того же запроса несколько раз, т. Е. Если это вызовет большую нагрузку, чем ваша база данных может обработать, или если это будет проблемой для запроса на возврат данных, которые немедленно перезаписываются в кеш, тогда вы, вероятно, захотите установить блокировку вокруг всего блока кода.

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

2 голосов
/ 14 апреля 2010

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

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

1 голос
/ 14 апреля 2010

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

Другой вопрос, однако, заключается в том, является ли потокобезопасным для данных . Нет гарантии, что каждый List<blabla> изолирован, это зависит от поставщика кеша. Поставщик кэша в памяти хранит объекты напрямую, поэтому существует риск коллизий, если какой-либо из потоков редактирует данные (добавляет / удаляет / меняет элементы в списке или изменяет свойства одного из элементов). Тем не менее, с сериализатором провайдера у вас все будет хорошо. Конечно, тогда требуется, чтобы blabla был сериализуемым ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...