(精华)2020年8月15日 C#基础知识点 cache缓存的实现
(精华)2020年8月15日 C#基础知识点 cache缓存的实现
静态字段缓存基本使用
/// <summary>
/// 1 客户端缓存-CDN缓存-反向代理缓存-本地缓存
/// 2 本地缓存原理和手写基础实现
/// 3 缓存更新/过期/多线程测试
/// 4 缓存类库封装和缓存应用总结
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{<!-- -->
try
{<!-- -->
Console.WriteLine("开发进阶/蜕变架构!");
{<!-- -->
Console.WriteLine("***************DBHelper*****************");
for (int i = 0; i < 5; i++) //会重复查询数据
{<!-- -->
Console.WriteLine($"获取{nameof(DBHelper)} {i}次 {DateTime.Now.ToString("yyyyMMdd HHmmss.fff")}");
List<Program> programList = null;
string key = $"{nameof(Program)}_DBHelper.Query_{123}";
programList = CustomCache.GetT<List<Program>>(key, () =>
{<!-- -->
return DBHelper.Query<Program>(123);
});
}
}
}
catch (Exception ex)
{<!-- -->
Console.WriteLine(ex.Message);
}
Console.Read();
}
/// <summary>
///模拟数据库查询
/// </summary>
public class DBHelper
{<!-- -->
/// <summary>
/// 1 耗时耗资源
/// 2 参数固定时,结果不变
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="index"></param>
/// <returns></returns>
public static List<T> Query<T>(int index)
{<!-- -->
Console.WriteLine("This is {0} Query", typeof(DBHelper));
long lResult = 0;
//耗时耗资源
for (int i = index; i < 1_000_000_000; i++)
{<!-- -->
lResult += i;
}
///只要Index不变 返回值是不变的!
List<T> tList = new List<T>();
for (int i = 0; i < index % 3; i++)
{<!-- -->
tList.Add(default(T));
}
return tList;
}
}
public class CustomCache
{<!-- -->
/// <summary>
/// 字典缓存
/// static:不会被Gc回收;
/// Private:不让外部访问他
/// </summary>
private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();
public static void Add(string key, object value)
{<!-- -->
CustomCacheDictionary.Add(key, value);
}
public static T Get<T>(string key)
{<!-- -->
return (T)CustomCacheDictionary[key];
}
public static bool Exists(string key)
{<!-- -->
return CustomCacheDictionary.ContainsKey(key);
}
public static T GetT<T>(string key, Func<T> func)
{<!-- -->
T t = default(T);
if (!Exists(key))
{<!-- -->
t = func.Invoke();
Add(key, t);
}
else
{<!-- -->
t = Get<T>(key);
}
return t;
}
}
cache缓存封装
/// <summary>
/// Cache manager interface
/// </summary>
public interface ICache
{<!-- -->
/// <summary>
/// Gets or sets the value associated with the specified key.
/// </summary>
/// <typeparam name="T">Type</typeparam>
/// <param name="key">The key of the value to get.</param>
/// <returns>The value associated with the specified key.</returns>
T Get<T>(string key);
/// <summary>
/// Adds the specified key and object to the cache.
/// </summary>
/// <param name="key">key</param>
/// <param name="data">Data</param>
/// <param name="cacheTime">Cache time</param>
void Add(string key, object data, int cacheTime = 30);
/// <summary>
/// Gets a value indicating whether the value associated with the specified key is cached
/// </summary>
/// <param name="key">key</param>
/// <returns>Result</returns>
bool Contains(string key);
/// <summary>
/// Removes the value with the specified key from the cache
/// </summary>
/// <param name="key">/key</param>
void Remove(string key);
/// <summary>
/// Clear all cache data
/// </summary>
void RemoveAll();
object this[string key] {<!-- --> get; set; }
int Count {<!-- --> get; }
}
/// <summary>
/// MemoryCacheCache
/// </summary>
public class MemoryCacheCache : ICache
{<!-- -->
public MemoryCacheCache() {<!-- --> }
protected ObjectCache Cache
{<!-- -->
get
{<!-- -->
return MemoryCache.Default;
}
}
/// <summary>
/// 读取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public T Get<T>(string key)
{<!-- -->
if (Cache.Contains(key))
{<!-- -->
return (T)Cache[key];
}
else
{<!-- -->
return default(T);
}
}
public object Get(string key)
{<!-- -->
return Cache[key];
}
/// <summary>
/// 增加缓存
/// </summary>
/// <param name="key"></param>
/// <param name="data"></param>
/// <param name="cacheTime">分钟</param>
public void Add(string key, object data, int cacheTime = 30)
{<!-- -->
if (data == null)
return;
var policy = new CacheItemPolicy();
policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);
Cache.Add(new CacheItem(key, data), policy);
}
/// <summary>
/// 是否包含
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool Contains(string key)
{<!-- -->
return Cache.Contains(key);
}
public int Count {<!-- --> get {<!-- --> return (int)(Cache.GetCount()); } }
/// <summary>
/// 单个清除
/// </summary>
/// <param name="key">/key</param>
public void Remove(string key)
{<!-- -->
Cache.Remove(key);
}
/// <summary>
/// 正则表达式移除
/// </summary>
/// <param name="pattern">pattern</param>
public void RemoveByPattern(string pattern)
{<!-- -->
var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
var keysToRemove = new List<String>();
foreach (var item in Cache)
if (regex.IsMatch(item.Key))
keysToRemove.Add(item.Key);
foreach (string key in keysToRemove)
{<!-- -->
Remove(key);
}
}
/// <summary>
/// 根据键值返回缓存数据
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object this[string key]
{<!-- -->
get {<!-- --> return Cache.Get(key); }
set {<!-- --> Add(key, value); }
}
/// <summary>
/// 清除全部数据
/// </summary>
public void RemoveAll()
{<!-- -->
foreach (var item in Cache)
Remove(item.Key);
}
}
缓存管理中心
public class CacheManager
{<!-- -->
#region Identity
private CacheManager()
{<!-- --> }
private static ICache cache = null;
static CacheManager()
{<!-- -->
Console.WriteLine("开始缓存的初始化.....");
//可以创建不同的cache对象
cache = (ICache)Activator.CreateInstance(typeof(MemoryCacheCache));
// 这里可以根据配置文件来选择
//cache = (ICache)Activator.CreateInstance(typeof(CustomerCache));
}
#endregion Identity
#region ICache
/// <summary>
/// 当前缓存数据项的个数
/// </summary>
public static int Count
{<!-- -->
get {<!-- --> return cache.Count; }
}
/// <summary>
/// 如果缓存中已存在数据项键值,则返回true
/// </summary>
/// <param name="key">数据项键值</param>
/// <returns>数据项是否存在</returns>
public static bool Contains(string key)
{<!-- -->
return cache.Contains(key);
}
/// <summary>
/// 获取缓存数据
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static T GetData<T>(string key)
{<!-- -->
return cache.Get<T>(key);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">缓存的项</param>
/// <param name="acquire">没有缓存的时候获取数据的方式</param>
/// <param name="cacheTime">单位分钟 默认30</param>
/// <returns></returns>
public static T Get<T>(string key, Func<T> acquire, int cacheTime = 30)
{<!-- -->
if (!cache.Contains(key))
{<!-- -->
T result = acquire.Invoke();
cache.Add(key, result, cacheTime);
}
return GetData<T>(key);
}
/// <summary>
/// 添加缓存数据。
/// 如果另一个相同键值的数据已经存在,原数据项将被删除,新数据项被添加。
/// </summary>
/// <param name="key">缓存数据的键值</param>
/// <param name="value">缓存的数据,可以为null值</param>
/// <param name="expiratTime">缓存过期时间间隔(单位:分钟)</param>
public static void Add(string key, object value, int expiratTime = 30)
{<!-- -->
if (Contains(key))
cache.Remove(key);
cache.Add(key, value, expiratTime);
}
/// <summary>
/// 删除缓存数据项
/// </summary>
/// <param name="key"></param>
public static void Remove(string key)
{<!-- -->
cache.Remove(key);
}
/// <summary>
/// 删除所有缓存数据项
/// </summary>
public static void RemoveAll()
{<!-- -->
cache.RemoveAll();
}
#endregion
}
缓存优化
/// <summary>
/// 永不过期:当前就是
/// 绝对过期:过了多长时间以后,就过期了 就不能用了
/// 滑动过期:设定好过期时间后,如果在有效期内使用过,就往后滑动
/// 1.Value;数据;
/// 2.过期时间点:
/// 3.滑动时间
/// 普通cache
/// </summary>
public class CustomCache
{<!-- -->
static CustomCache() //CLR调用 整个进程执行且只执行一次
{<!-- -->
Task.Run(() => //
{<!-- -->
while (true) //死循环来判断
{<!-- -->
try
{<!-- -->
List<string> delKeyList = new List<string>();
lock (obj_Lock)
{<!-- -->
foreach (var key in CustomCacheDictionary.Keys)
{<!-- -->
DataModel model = CustomCacheDictionary[key];
if (model.Deadline < DateTime.Now && model.ObsloteType != ObsloteType.Never)
{<!-- -->
delKeyList.Add(key);
}
}
}
delKeyList.ForEach(key => Remove(key));
}
catch (Exception ex)
{<!-- -->
Console.WriteLine(ex.Message);
throw;
}
}
});
}
/// <summary>
/// static:不会被Gc回收;
/// Private:不让外部访问他
/// </summary>
private static Dictionary<string, DataModel> CustomCacheDictionary = new Dictionary<string, DataModel>();
private static readonly object obj_Lock = new object();
/// <summary>
/// 默认你是不过期
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public static void Add(string key, object value)
{<!-- -->
lock (obj_Lock)
CustomCacheDictionary.Add(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Never
});
}
/// <summary>
/// 绝对过期
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="timeOutSecond"></param>
public static void Add(string key, object value, int timeOutSecond) //3000
{<!-- -->
lock (obj_Lock)
CustomCacheDictionary.Add(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Absolutely,
Deadline = DateTime.Now.AddSeconds(timeOutSecond)
}); ;
}
public static void Add(string key, object value, TimeSpan durtion)
{<!-- -->
lock (obj_Lock)
CustomCacheDictionary.Add(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Relative,
Deadline = DateTime.Now.Add(durtion),
Duraton = durtion
}); ; ;
}
//清楚所有缓存,殃及池鱼!
public static void RemoveAll()
{<!-- -->
lock (obj_Lock)
CustomCacheDictionary.Clear();//字典中的所有内容全部被清理到
}
public static void Remove(string key)
{<!-- -->
lock (obj_Lock)
CustomCacheDictionary.Remove(key);
}
public static void RemoveCondition(Func<string, bool> func)
{<!-- -->
List<string> keyList = new List<string>();
lock (obj_Lock)
foreach (var key in CustomCacheDictionary.Keys)
{<!-- -->
if (func.Invoke(key))
{<!-- -->
keyList.Add(key);
}
}
keyList.ForEach(s => Remove(s));
}
public static T Get<T>(string key)
{<!-- -->
return (T)(CustomCacheDictionary[key]).Value;
}
public static bool Exists(string key)
{<!-- -->
if (CustomCacheDictionary.ContainsKey(key))
{<!-- -->
DataModel model = CustomCacheDictionary[key];
if (model.ObsloteType == ObsloteType.Never)
{<!-- -->
return true;
}
else if (model.Deadline < DateTime.Now) //
{<!-- -->
lock (obj_Lock)
{<!-- -->
CustomCacheDictionary.Remove(key);
return false;
}
}
else
{<!-- -->
if (model.ObsloteType == ObsloteType.Relative)
{<!-- -->
model.Deadline = DateTime.Now.Add(model.Duraton);
}
return true;
}
}
else
{<!-- -->
return false;
}
}
public static T GetT<T>(string key, Func<T> func)
{<!-- -->
T t = default(T);
if (!Exists(key))
{<!-- -->
t = func.Invoke();
Add(key, t);
}
else
{<!-- -->
t = Get<T>(key);
}
return t;
}
}
/// <summary>
/// 线程安全cache
/// </summary>
public class CustomCacheNew
{<!-- -->
static CustomCacheNew() //
{<!-- -->
Task.Run(() => //
{<!-- -->
while (true) //死循环来判断
{<!-- -->
try
{<!-- -->
//Thread.Sleep(60 * 1000 * 10); //十分钟后开始清理缓存
List<string> delKeyList = new List<string>();
foreach (var key in CustomCacheDictionary.Keys)
{<!-- -->
DataModel model = CustomCacheDictionary[key];
if (model.Deadline < DateTime.Now && model.ObsloteType != ObsloteType.Never) //
{<!-- -->
delKeyList.Add(key);
}
}
delKeyList.ForEach(key => Remove(key));
}
catch (Exception ex)
{<!-- -->
Console.WriteLine(ex.Message);
throw;
}
}
});
}
/// <summary>
/// static:不会被Gc回收;
/// Private:不让外部访问他
///
/// 线程安全字典
/// </summary>
private static ConcurrentDictionary<string, DataModel> CustomCacheDictionary = new ConcurrentDictionary<string, DataModel>();
/// <summary>
/// 默认你是不过期
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public static void Add(string key, object value)
{<!-- -->
CustomCacheDictionary.TryAdd(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Never
});
}
/// <summary>
/// 绝对过期
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="timeOutSecond"></param>
public static void Add(string key, object value, int timeOutSecond) //3000
{<!-- -->
CustomCacheDictionary.TryAdd(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Absolutely,
Deadline = DateTime.Now.AddSeconds(timeOutSecond)
}); ;
}
public static void Add(string key, object value, TimeSpan durtion)
{<!-- -->
CustomCacheDictionary.TryAdd(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Relative,
Deadline = DateTime.Now.Add(durtion),
Duraton = durtion
}); ; ;
}
//清楚所有缓存,殃及池鱼!
public static void RemoveAll()
{<!-- -->
CustomCacheDictionary.Clear();//字典中的所有内容全部被清理到
}
public static void Remove(string key)
{<!-- -->
DataModel data = null;
CustomCacheDictionary.TryRemove(key, out data);
}
public static T Get<T>(string key)
{<!-- -->
return (T)(CustomCacheDictionary[key]).Value;
}
/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Exists(string key)
{<!-- -->
if (CustomCacheDictionary.ContainsKey(key))
{<!-- -->
DataModel model = CustomCacheDictionary[key];
if (model.ObsloteType == ObsloteType.Never)
{<!-- -->
return true;
}
else if (model.Deadline < DateTime.Now) //
{<!-- -->
DataModel data = null;
CustomCacheDictionary.TryRemove(key, out data);
return false;
}
else
{<!-- -->
if (model.ObsloteType == ObsloteType.Relative)
{<!-- -->
model.Deadline = DateTime.Now.Add(model.Duraton);
}
return true;
}
}
else
{<!-- -->
return false;
}
}
public static T GetT<T>(string key, Func<T> func)
{<!-- -->
T t = default(T);
if (!Exists(key))
{<!-- -->
t = func.Invoke();
Add(key, t);
}
else
{<!-- -->
t = Get<T>(key);
}
return t;
}
}
internal class DataModel
{<!-- -->
public object Value {<!-- --> get; set; }
public ObsloteType ObsloteType {<!-- --> get; set; }
public DateTime Deadline {<!-- --> get; set; }
public TimeSpan Duraton {<!-- --> get; set; }
}
public enum ObsloteType
{<!-- -->
Never,
Absolutely,
Relative
}
/// <summary>
/// 解决性能问题
/// </summary>
public class CustomCacheNewproblem
{<!-- -->
private static List<Dictionary<string, DataModel>> dicCacheList = new List<Dictionary<string, DataModel>>();
private static List<object> lockList = new List<object>();
public static int CupNum = 0;
static CustomCacheNewproblem()
{<!-- -->
CupNum = 3;//模拟获取获取CPU片数
//动态生成字典
for (int i = 0; i < CupNum; i++)
{<!-- -->
dicCacheList.Add(new Dictionary<string, DataModel>()); //CPU 有几片 就来几个字典
lockList.Add(new object());//没个字典对应一个锁
}
Task.Run(() => //
{<!-- -->
while (true) //死循环来判断
{<!-- -->
try
{<!-- -->
for (int i = 0; i < CupNum; i++)
{<!-- -->
lock (lockList[i])
{<!-- -->
//Thread.Sleep(60 * 1000 * 10); //十分钟后开始清理缓存
List<string> delKeyList = new List<string>();
foreach (var key in dicCacheList[i].Keys)
{<!-- -->
DataModel model = dicCacheList[i][key];
if (model.Deadline < DateTime.Now && model.ObsloteType != ObsloteType.Never) //
{<!-- -->
delKeyList.Add(key);
}
}
delKeyList.ForEach(key => dicCacheList[i].Remove(key));
}
}
}
catch (Exception ex)
{<!-- -->
Console.WriteLine(ex.Message);
throw;
}
}
});
}
/// <summary>
/// 默认你是不过期
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public static void Add(string key, object value)
{<!-- -->
int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
int index = hash % CupNum;
lock (lockList[index])
dicCacheList[index].Add(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Never
});
}
/// <summary>
/// 绝对过期
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="timeOutSecond"></param>
public static void Add(string key, object value, int timeOutSecond) //3000
{<!-- -->
int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
int index = hash % CupNum;
lock (lockList[index])
dicCacheList[index].Add(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Absolutely,
Deadline = DateTime.Now.AddSeconds(timeOutSecond)
}); ;
}
public static void Add(string key, object value, TimeSpan durtion)
{<!-- -->
int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
int index = hash % CupNum;
lock (lockList[index])
dicCacheList[index].Add(key, new DataModel()
{<!-- -->
Value = value,
ObsloteType = ObsloteType.Relative,
Deadline = DateTime.Now.Add(durtion),
Duraton = durtion
}); ; ;
}
//清楚所有缓存,殃及池鱼!
public static void RemoveAll()
{<!-- -->
for (int i = 0; i < CupNum; i++)
{<!-- -->
dicCacheList[i].Clear();
}
}
public static void Remove(string key)
{<!-- -->
int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
int index = hash % CupNum;
if (dicCacheList[index].ContainsKey(key))
{<!-- -->
dicCacheList[index].Remove(key);
}
}
public static T Get<T>(string key)
{<!-- -->
int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
int index = hash % CupNum;
return (T)(dicCacheList[index][key]).Value;
}
/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Exists(string key)
{<!-- -->
int hash = key.GetHashCode() * (-1); //只要字符串变,hash值不变!
int index = hash % CupNum;
if (dicCacheList[index].ContainsKey(key))
{<!-- -->
DataModel model = dicCacheList[index][key];
if (model.ObsloteType == ObsloteType.Never)
{<!-- -->
return true;
}
else if (model.Deadline < DateTime.Now) //
{<!-- -->
dicCacheList[index].Remove(key);
return false;
}
else
{<!-- -->
if (model.ObsloteType == ObsloteType.Relative)
{<!-- -->
model.Deadline = DateTime.Now.Add(model.Duraton);
}
return true;
}
}
else
{<!-- -->
return false;
}
}
public static T GetT<T>(string key, Func<T> func)
{<!-- -->
T t = default(T);
if (!Exists(key))
{<!-- -->
t = func.Invoke();
Add(key, t);
}
else
{<!-- -->
t = Get<T>(key);
}
return t;
}
}