asp.net缓存多线程锁定Web部件

本文关键字:Web 部件 锁定 多线程 net 缓存 asp | 更新日期: 2023-09-27 17:58:43

我有以下场景:

假设我们有两个不同的Web部件在同一数据上运行——一个是饼图,另一个是数据表。在他们的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
       }
    }

由于两个Web部件都对相同的数据进行操作,所以对我来说执行两次代码是没有意义的。

让一个web部件与另一个进行通信的最佳方法是什么?"我已经在获取数据,所以只需等待,直到我将其放入缓存"?

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

asp.net缓存多线程锁定Web部件

您需要利用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;
    }
  }
}

为什么不加载数据并将其放入Global.asax中Application_Start的缓存中,那么就不需要锁定了,因为锁定缓存是一件很严重的事情。

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

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

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

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