我有以下情况:
假设我们有两个不同的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部件与另一个进行通信的最佳方法是什么?“我已经在提取数据,所以只要等到我将其放入缓存”?
我一直在考虑互斥锁,锁定,为缓存项分配临时值并等待临时值更改...许多选项 - 我应该使用哪一个。
答案 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
?如果没有,请启动它。如果是这样,你不应该启动另一个,所以你可能想要注册你自己的事件处理程序,以便在它完成时捕获......