Многопоточность кеша asp.net блокирует веб-части - PullRequest
2 голосов
/ 09 июня 2011

У меня есть следующий сценарий:

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

protected void Page_Load(object sender, EventArgs e)
    { 
       if (Cache["dtMine" + "_" + Session["UserID"].ToString()]==null)
       {
         ...
         Page.RegisterAsyncTask(new PageAsyncTask(
             new BeginEventHandler(BeginGetByUserID),
             new EndEventHandler(EndGetByUserID), 
             null, args, true));
       }
      else 
       {
         get data from cache and bind to controls of the webpart
       }
    }

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

Каков наилучший подход к тому, чтобы одна веб-часть взаимодействовала с другой "я уже извлекаю данные, поэтому просто подождите, пока я не помещу их в кэш"? ​​

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

Ответы [ 3 ]

2 голосов
/ 09 июня 2011

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

Обновление:

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

protected void Page_Load(object sender, EventArgs e)
{ 
   string key = "dtMine" + "_" + Session["UserID"].ToString();

   DataProxy proxy = null;

   lock (Cache)
   {
     proxy = Cache[key];
     if (proxy == null)
     {
       proxy = new DataProxy();
       Cache[key] = proxy;
     }
   }

   object data = proxy.GetData();
}

private class DataProxy
{
  private object data = null;

  public object GetData()
  {
    lock (this)
    {
      if (data == null)
      {
        data = LoadData(); // This is what actually loads the data.
      }
      return data;
    }
  }
}
1 голос
/ 12 февраля 2012

Почему бы вам не загрузить данные и не поместить их в кеш в Application_Start в Global.asax, тогда блокировка не понадобится, поскольку блокировка кеша - серьезная вещь.

0 голосов
/ 09 июня 2011

Вы можете использовать мьютекс вокруг теста Cache["key"]==null:

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

Но это заблокировало бы поток, выполняющий метод Page_Load() - возможно, это плохо.

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

...