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部件与另一个进行通信的最佳方法是什么?"我已经在获取数据,所以只需等待,直到我将其放入缓存"?
我一直在考虑互斥、锁定、为缓存项分配临时值,并等待临时值更改。。。许多选项-我应该使用哪一个。
您需要利用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
是否已经启动?如果不是,启动它。如果是,你不应该启动另一个,所以你可能想注册自己的事件处理程序,以便在它完成时捕获。。。