在asp.net中我們可以把我們的一些待用資料通過Cache來緩衝,已提高網站效能。下面是msdn上一個使用Cache的例子。其中有可很意思的功能是
我們可以給快取項目指定一個回調,當快取項目被remove的時候將調用回調方法通知我們。我們公司的一個應用使用了這個方法用來緩衝對資料庫的一些更新,來避免頻繁操作資料庫已提高效能。當緩衝被清除的時候在調用回調吧緩衝的資料集中寫入資料庫。這種方法當並發訪問量大大時候就會出現阻塞線程的問題。從而導致cpu狂漲。最後可能耗盡所有線程池線程。
代碼<html>
<Script runat=server language="C#">
static bool itemRemoved = false;
static CacheItemRemovedReason reason;
CacheItemRemovedCallback onRemove = null;
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r){
itemRemoved = true;
reason = r;
}
public void AddItemToCache(Object sender, EventArgs e) {
itemRemoved = false;
onRemove = new CacheItemRemovedCallback(this.RemovedCallback);
if (Cache["Key1"] == null)
Cache.Add("Key1", "Value 1", null, DateTime.Now.AddSeconds(60), TimeSpan.Zero, CacheItemPriority.High, onRemove);
}
public void RemoveItemFromCache(Object sender, EventArgs e) {
if(Cache["Key1"] != null)
Cache.Remove("Key1");
}
</Script>
<body>
<Form runat="server">
<input type=submit OnServerClick="AddItemToCache" value="Add Item To Cache" runat="server"/>
<input type=submit OnServerClick="RemoveItemFromCache" value="Remove Item From Cache" runat="server"/>
</Form>
<% if (itemRemoved) {
Response.Write("RemovedCallback event raised.");
Response.Write("<BR>");
Response.Write("Reason: <B>" + reason.ToString() + "</B>");
}
else {
Response.Write("Value of cache key: <B>" + Server.HtmlEncode(Cache["Key1"] as string) + "</B>");
}
%>
</body>
</html>
原因是Cache其實是個全域對象,所以對Cache的訪問都會在內部通過一個ReaderWriterLock進行同步。在Remove快取項目調用回調方法的時候,由於回調方法又訪問資料庫。結果導致Remove快取項目長時間的佔用鎖,導致其他請求無法讀取寫入緩衝,從而阻塞線程池中其他線程。所以快取項目的回調方法不適合調用長時間的操作。最好是移除快取項目後,在自己調用後續操作。避免鎖定爭用。