Неблокирующее внутрипроцессное хранилище состояний сеанса ASP.NET - PullRequest
15 голосов
/ 08 сентября 2010

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

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

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

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

Любые идеи или примеры реализации?

Ответы [ 5 ]

12 голосов
/ 18 сентября 2010

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

Подумайте о бедных парнях, которым придетсяподдержите свой код вниз по линии.Тот факт, что Session сериализует запросы таким образом, означает, что разработчикам ASP.NET часто не нужно слишком беспокоиться о безопасности потоков.

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

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

6 голосов
/ 12 сентября 2010

Если вы читаете только из сеанса на данной странице, вы можете использовать директиву Page:

<%@ Page EnableSessionState="ReadOnly" %>

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

Поскольку внутренне используется блокировка ReaderWriter, блокировка чтения блокирует блокировку записи, но блокировка чтения не блокирует блокировку чтения.Блокировка писателя блокирует все блокировки чтения и записи.

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

4 голосов
/ 17 сентября 2010

но код выглядит подозрительно сложным только с целью снятия блокировки.

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

Я предлагаю вам прочитать немного больше о том, как работает концепция сессии в asp.net. Учтите, что способ, которым он был разработан, предполагает чтение всего сеанса один раз в запросе, а затем запись измененного сеанса один раз.

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

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

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

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

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

1 голос
/ 18 сентября 2010

Я предлагаю вам перейти на Режим SQL Server . Сеансы SQL Server позволяют любому количеству запросов от нескольких веб-серверов использовать один сеанс. Насколько я знаю, SQL Server внутренне управляет механизмом блокировки, который чрезвычайно эффективен. У вас также есть дополнительный бонус, поскольку у вас меньше места в памяти. И вам не нужно писать HttpModule для его запуска.

1 голос
/ 17 сентября 2010

Вам придется написать свой собственный поставщик состояния сеанса, это не так сложно, как кажется.Я бы не рекомендовал вам использовать Cache, потому что, как сказал Дарин, Cache недостаточно надежен, например, элементы, срок хранения которых истекает и / или удаляется из кэша, когда не хватает памяти.блокировать элементы сеанса вместо всего состояния сеанса (которое подходит нам в нашем проекте) при записи, необходимый код для этого должен быть в реализации ISessionStateItemCollection (в индексаторе), что-то вроде этого:

public object this[string name]
{
    get
    {
        //no lock, just returning item (maybe immutable, it depends on how you use it)
    }
    set
    {
        //lock here
    }
}

Для нашего проекта мы создали реализацию, которая хранит элементы в AppFabric Cache и использует методы GetAndLock, PutAndUnlock для кэша.Если у вас есть внутрипроцессный сеанс, вам может понадобиться lock(smthg) {}

Надеюсь, это поможет.

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