在优化一个Web Service客户端应用程序时,为了减少访问服务压力,提高客户端的响应速度,写了一个精简的缓存器,实现一次读取,重复使用,定时淘汰功能。代码简洁明了,可见C#功能之强大。
一、缓存器代码
/// <summary>
/// 一个超时淘汰的缓存器
/// </summary>
public class Caches
{
private uint timeOut = 60 * 5;
private System.Threading.Timer outTimer = null;
public Caches()
{
outTimer = new System.Threading.Timer(new System.Threading.TimerCallback(OutTimerCallback), null, 60 * 1000, 60 * 1000);
}
/// <summary>
/// 超时值,以秒为单位
/// </summary>
public uint TimeOut
{
get
{
return timeOut;
}
set
{
timeOut = value;
}
}
/// <summary>
/// 依据键值存、取缓存内容
/// </summary>
/// <param name="hash"></param>
/// <returns></returns>
public object this[string key]
{
get
{
if (string.IsNullOrEmpty(key) || !CacheTime.ContainsKey(key))
{
return null;
}
object val = null;
lock (CacheTime)
{
val = CacheTable[key];
CacheTime[key] = DateTime.Now;
}
return val;
}
set
{
if (string.IsNullOrEmpty(key))
{
throw (new Exception("参数不能为空!"));
}
if (value != null)
{
lock (CacheTime)
{
this.CacheTable[key] = value;
this.CacheTime[key] = DateTime.Now;
}
}
else
{
Remove(key);
}
}
}
/// <summary>
/// 是否包含指定键值的缓存值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool ContainsKey(string key)
{
return this.CacheTable.ContainsKey(key);
}
/// <summary>
/// 删除指定缓存值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool Remove(string key)
{
if (string.IsNullOrEmpty(key) || !CacheTime.ContainsKey(key))
{
return false;
}
bool result = false;
{
lock (CacheTime)
{
result = this.CacheTable.Remove(key);
if (result)
{
this.CacheTime.Remove(key);
}
}
}
return result;
}
/// <summary>
/// 清空缓存
/// </summary>
public void Clear()
{
lock (CacheTime)
{
this.CacheTable.Clear();
this.CacheTime.Clear();
}
}
/// <summary>
/// 记录缓存值
/// </summary>
private Dictionary<string, object> CacheTable = new Dictionary<string, object>();
/// <summary>
/// 记录缓存值最后一次访问的时间
/// </summary>
private Dictionary<string, DateTime> CacheTime = new Dictionary<string, DateTime>();
/// <summary>
/// 定时检查并淘汰不活动的缓存数据
/// </summary>
/// <param name="state"></param>
private void OutTimerCallback(object state)
{
DateTime now = DateTime.Now;
lock (CacheTime)
{
List<string> keys = new List<string>();
foreach (KeyValuePair<string, DateTime> CacheTimeItem in CacheTime)
{
if (CacheTimeItem.Value.AddSeconds(this.timeOut) <= now)
{
keys.Add(CacheTimeItem.Key);
}
}
foreach (string key in keys)
{
if (this.CacheTable.Remove(key))
{
this.CacheTime.Remove(key);
}
}
}
}
}
二、应用示例:
public class MgrTask
{
private Caches m_Caches;
private MgrTask()
{
//by sasw 本地创建一个缓存,缓存从服务器读取的数据。2009.7.9
m_Caches = new Caches();
#if DEBUG
m_Caches.TimeOut = 30;
#else
m_Caches.TimeOut = 5 * 60;
#endif
}
public List<taskAnalysisPc> ListTaskPc(int batch_id, int rule_id)
{
string key = Utility.getMd5Hash(string.Format("ListTaskPc({0},{1})", batch_id, rule_id));
if (m_Caches.ContainsKey(key))
{
return (List<taskAnalysisPc>)m_Caches[key];
}
getTaskAnalysisPcList actor = new getTaskAnalysisPcList();
List<taskAnalysisPc> list = new List<taskAnalysisPc>();
for (int k = 0; k < 3; k++)
{
try
{
actor.Url = MgrServices.PrefixURL + MgrServices.GetTaskAnalysiaPC;
taskAnalysisPc[] val = actor.CallgetTaskAnalysisPcList(MgrLogon.Token, batch_id, rule_id);
if (val != null && val.Length > 0)
{
list.AddRange(val);
}
m_Caches[key] = list;
break;
}
catch (Exception ex)
{
if (k == 2) System.Diagnostics.Debug.Assert(false, string.Format("访问/"{0}/"失败。", actor.Url), string.Format("Source:{0}/r/nMessage:{1}/r/nStackTrace:{2}/r/nData:{3}/r/n", ex.Source, ex.Message, ex.StackTrace, ex.Data));
}
}
return list;
}
}
三、代码中 Utility.getMd5Hash()的定义:
/// <summary>
/// 计算hash
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string getMd5Hash(string input)
{
// Create a new instance of the MD5CryptoServiceProvider object.
MD5 md5Hasher = MD5.Create();
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}