asp.net缓存多线程锁定webparts

时间:2011-06-09 16:37:15

标签: c# asp.net multithreading caching web-parts

我有以下情况:

假设我们有两个不同的webparts在相同的数据上运行 - 一个是饼图,另一个是数据表。 在他们的Page_Load中,他们异步地从数据库加载数据,并在加载时将其放在应用程序缓存中以供进一步使用或由其他Web部件使用。因此,每个Web部件都有类似的代码:

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
       }
    }

由于两个webparts都使用相同的数据,因此我执行代码两次没有意义。

让一个Web部件与另一个进行通信的最佳方法是什么?“我已经在提取数据,所以只要等到我将其放入缓存”?

我一直在考虑互斥锁,锁定,为缓存项分配临时值并等待临时值更改...许多选项 - 我应该使用哪一个。

3 个答案:

答案 0 :(得分:2)

您需要利用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 :(得分:1)

为什么不加载数据并将其放在Global.asax的Application_Start中的缓存中,因此不需要锁定,因为锁定Cache是​​一件严肃的事情。

答案 2 :(得分:0)

您可以在测试Cache["key"]==null周围使用互斥锁:

第一个线程获取锁,测试并发现缓存中没有任何内容,然后去获取数据。第二个线程必须等待第一个线程释放互斥锁。一旦第二个线程进入互斥锁,它就会测试,看到数据在那里然后继续。

但是这会锁定运行Page_Load()方法的线程 - 可能是件坏事。

也许更好的解决方案是测试是否已启动获取数据的PageAsyncTask?如果没有,请启动它。如果是这样,你不应该启动另一个,所以你可能想要注册你自己的事件处理程序,以便在它完成时捕获......