что будет если не заблокировать словарь при его изменении? о кеше asp.net - PullRequest
0 голосов
/ 18 декабря 2009

извините, у меня много вопросов о блокировке / кэше. = _ = ..

-> 1. о кеше, я знаю, что кэш в asp.net является поточно-ориентированным, простой код, который я обычно использую, -

    IList<User> user= HttpRuntime.Cache["myCacheItem"] as IList<User>;
    if (user == null)
    { 
       //should i have a lock here?
       //lock(some_static_var){...}
       HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase();
    }

    return user;

следует использовать блокировку в коде?

-> -> 1.1 если я использую, может быть, я должен объявить много lockitem? я видел некоторую реализацию на сервере сообщества, он использует статический словарь для хранения элемента блокировки, это хорошая идея? потому что я обеспокоен тем, что в словаре может быть слишком много блокировок и это может замедлить работу системы.

-> -> 1.2, если я не буду использовать, что произойдет? просто возможно два или более потоков обращаются к GetDateFromDateBase()? если только это, я думаю, что я могу снять блокировку.

-> 2.У меня есть общий словарь, хранящийся в кэше, я должен его изменить (добавить / обновить / удалить). и я просто использую его, чтобы получить значение, как dic.trygetvalue (ключ), не зацикливайте его.

-> -> 2.1, если я могу гарантировать, что изменение происходит только в одном потоке, например,
a.aspx -> прочитать словарь из кэша и отобразить на странице, открытой для пользователя
b.ashx -> изменит словарь при его вызове (цикл за 5 минут), частное использование

я должен использовать блокировку в a / b? заблокировать читатель и писатель?
-> -> -> 2.11, если я не использую блокировку, что произойдет? Вызовет ли исключение, когда читатель и писатель получат доступ одновременно?
-> -> -> 2.12, если я просто заблокирую писателя в b.ashx, что произойдет? будет ли заблокирован ридер в .aspx? и как лучше всего справляться с этой ситуацией?

-> -> 2.2, если читатель и писатель произошли в многопоточном доступе. они оба на общедоступной странице.
a.aspx -> только что прочитал из кеша
b.aspx -> изменить словарь

что делать? заблокировать все?

-> -> 2.3, если я реализую новую функцию добавления словаря:
это просто скопировать текущий словарь в новый словарь, а затем добавить новый элемент или изменить и, наконец, вернуть новый dic, он решит проблему параллелизма?

решит ли хеш-таблица эти проблемы?

как определить, что предмет должен быть заблокирован? я думаю, что я не прав в этих вещах = _ =.

-> 3. последний вопрос .. у меня есть два веб-приложения
a -> показать сеть
b -> отобразить некоторые настройки
у них обоих есть собственный кеш, что я могу сделать одновременно с двумя кешами?
будет ли операция в [2.1] правильной или другой операцией? (я проверяю memcached, но он работает слишком медленно, чем в веб-приложении, поэтому я использую только две)

спасибо, что прочитали все -_-...
хотел бы ты знать, что я говорю :) 1031 *

Обновление ======================================== ==============
Спасибо за ответ Аарона. после прочтения его ответа я пытаюсь ответить самому себе.
1. о кеше, если данные не изменятся, он может сначала прочитать в кеш в Application_Start (global.asax).
1.1 Если блокировка, я должен добавить блокировку начала при чтении данных, а не только при записи. элемент блокировки должен быть статичным, но я также не чувствую уверенности в отношении 1.1.
1.2 Да, если вы можете предположить, что код просто считывает дату из базы данных, а затем вставляет в кеш и не изменится (верно? -_-). результат этого может быть прочитан несколько раз из базы данных. Я думаю, что это не большая проблема.

2. Общий словарь записи не является потокобезопасным, поэтому он должен быть заблокирован при изменении. Чтобы решить эту проблему, я могу использовать неизменный словарь.
но если я использую ConcurrentDictionary (threadsafe при чтении / записи) в .net4.0 или сам реализую новый словарь (использую блокировку чтения-записи), это решит? Нужно ли снова его блокировать при изменении? код похож на

ConcurrentDictionary user= HttpRuntime.Cache["myCacheItem"] as ConcurrentDictionary;
if (user == null)
{ 
   //is it safe when the user is ConcurrentDictionary?
   HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase();
}
else
{
    //is it safe when the user is ConcurrentDictionary?
    user["1"] = a_new_user;
}


3. вопрос в том, что у меня есть небольшое приложение, такое как stroe, у него есть два веб-приложения: одно - сайт магазина (A), а другое - сайт управления (B), поэтому мне нужно одновременно использовать два веб-кэша, например, если я изменяю цену продукта в B, как я могу уведомить сайт A об изменении / удалении кэша? (я знаю, что кэш в A может установить короткое замыкание, но это не быстро, поэтому я хочу знать, есть ли там внутренний поддержка в asp.net или просто как вопрос 2.1? есть страница aspx / ashx для вызова?)

1 Ответ

6 голосов
/ 18 декабря 2009

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

Однако, если вы пытаетесь выполнить то, что должно быть атомарной операцией - например, проверять наличие элемента и добавлять его, если он не существует - тогда вам нужно синхронизировать или сериализовать доступ. Поскольку блокировка должна быть глобальной, обычно лучше объявить static readonly object в вашем global.asax и заблокировать ее перед выполнением атомарной операции. Обратите внимание, что вам следует заблокировать до чтения и снять блокировку только после записи , поэтому ваша гипотетическая блокировка в приведенном выше примере на самом деле происходит слишком поздно.

Вот почему многие веб-приложения не лениво загружают кэш; вместо этого они выполняют загрузку в методе Application_Start. По крайней мере, размещение пустого словаря в кеше избавит вас от необходимости проверять null, и таким образом вам не придется синхронизироваться, потому что вы будете обращаться к элементу кэша только один раз (но читайте дальше).

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

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

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

Это должно ответить на вопросы 1-2; Извините, но я не совсем понимаю, что вы спрашиваете в # 3. Все приложения ASP.NET создаются в своих собственных доменах приложений, так что на самом деле нет никаких проблем с параллелизмом, о которых можно говорить, потому что ничего не передается (если только вы на самом деле не используете какой-либо метод IPC, и в этом случае все будет честной игрой).

Правильно ли я понял ваши вопросы? Это помогает?

...