介绍
缓存,在一定程度上,是可以提高程序性能的一个解决方案,比如,我们从数据库读数据,如果每次都从数据库读取的话,每次都需要进行 网络IO操作,需要等待网络数据返回,如果在60s内,有成千上百个访问进行同样的数据进行查询,将会更加耗时耗力……如果,我们将第一个访问者查询的数据,先保存起来,然后60s内,其他访问者均读取保存起来的数据,这样不需要再去重新查询数据库,减少一定的网络操作,所以说,缓存,一定程度上可以提高程序性能!
这里将介绍如何使用C# 中的MemoryCache 来实现内存缓存!
引入 system.running.cache类库
Cache 实现
定义一个ICache 接口
public interface ICache { /// <summary> /// 获取缓存项,当没有缓存时,使用factory提供的值 /// </summary> /// <param name="key"></param> /// <param name="factory"></param> /// <returns></returns> object Get(string key, Func<string, object> factory); /// <summary> /// 获取缓存项,没有缓存时返回默认数据 /// </summary> /// <param name="key"></param> /// <returns></returns> object GetOrDefault(string key); /// <summary> /// 设置缓存项并设置过期时间 /// </summary> /// <param name="key">key</param> /// <param name="value">值</param> /// <param name="slidingExpireTime">多久未访问则失效</param> /// <param name="absoluteExpireTime">超时失效</param> void Set(string key, object value, TimeSpan? slidingExpireTime = null,TimeSpan?absoluteExpireTime=null); /// <summary> /// 移除缓存项 /// </summary> /// <param name="key"></param> void Remove(string key); /// <summary> /// 清空缓存 /// </summary> void Clear(); }
该接口提供了获取缓存、设置缓存、移除缓存和清空缓存操作,且 get 方法,如果缓存中没有项,则可以通过 factory返回数据并保存到缓存!
缓存基类:CacheBase
public abstract class CacheBase : ICache { protected readonly object SyncObj = new object(); protected CacheBase() { } public virtual object Get(string key, Func<string, object> factory) { var cacheKey = key; var item = this.GetOrDefault(key); if (item == null) { lock (this.SyncObj)// TODO: 为何要锁定 { item = this.GetOrDefault(key); if (item != null) { return item; } item = factory(key); if (item == null) { return null; } this.Set(cacheKey, item); } } return item; } public abstract object GetOrDefault(string key); public abstract void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null); public abstract void Remove(string key); public abstract void Clear(); public virtual void Dispose() { } }
缓存基类为虚类,只实现了 Get(string key, Func<string, object> factory)
方法, 这里进行了锁定,主要是为了多线程操作,在设置缓存的时候,只会有一个访问者在设置缓存项,其他方法均为虚方法,等待具体实现类实现
缓存具体实现类:DemoCache
public class DemoCache : CacheBase { private MemoryCache _memoryCache; public DemoCache() : base() { this._memoryCache = new MemoryCache("DemoCache"); } public override object GetOrDefault(string key) { return this._memoryCache.Get(key); } public override void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null) { if (value == null) { throw new Exception("Can not insert null values to the cache!"); } var cachePolicy = new CacheItemPolicy(); if (absoluteExpireTime != null) { cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.Add(absoluteExpireTime.Value); } else if (slidingExpireTime != null) { cachePolicy.SlidingExpiration = slidingExpireTime.Value; } else { cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.Add(TimeSpan.FromSeconds(60)); } this._memoryCache.Set(key, value, cachePolicy); } public override void Remove(string key) { this._memoryCache.Remove(key); } public override void Clear() { // 将原来的释放,并新建一个cache this._memoryCache.Dispose(); this._memoryCache = new MemoryCache("DemoCache"); } public override void Dispose() { this._memoryCache.Dispose(); base.Dispose(); } }
在具体的设置缓存项中,设置了,如果过期时间为空的话,则设置多久为访问超时,如果两则都为空的话,则设置 定时超时,这里默认为 60 秒。
清空缓存的时候,则释放 memorycache,并新建具体cache实例来实现
使用缓存
定义一个方法,用来取数据
private static int GetCacheRandom(ICache cache) { var cacheItem = cache.Get("random", (key) => { Random random = new Random(); return random.Next(1, 1000); }); return int.Parse(cacheItem.ToString()); }
这个方法,提供了取1到1000的随机值,并保存到缓存中。
定义一个现实函数,用来现实 何时取到的数字
private static void ShowCacheItem(int value) { Console.WriteLine("{0} 取数:{1}",DateTime.Now.ToString("HH:mm:ss"), value); }
具体使用
static void Main(string[] args) { ICache cache = new DemoCache(); var cacheItem = GetCacheRandom(cache); Console.Write("第一次取值 "); ShowCacheItem(cacheItem); Stopwatch watch=new Stopwatch(); watch.Start(); while (true) { if (watch.ElapsedMilliseconds < 10000) { continue; } cacheItem = GetCacheRandom(cache); Console.Write("10s后取值 "); ShowCacheItem(cacheItem); break; } while (true) { if (watch.ElapsedMilliseconds < 40000) { continue; } cacheItem = GetCacheRandom(cache); Console.Write("40s后取值 "); ShowCacheItem(cacheItem); break; } while (true) { if (watch.ElapsedMilliseconds < 70000) { continue; } cacheItem = GetCacheRandom(cache); Console.Write("70s后取值,此时应该是新值 "); ShowCacheItem(cacheItem); break; } watch.Stop(); Console.WriteLine("输入任意键退出!"); Console.ReadKey(); }
首先建立 DemoCache的实例,然后获取一次数值,然后10s取一次数据,40s取一次数据,70s取一次数据,如果缓存生效,则前三次,即第一次,10s取得一次,40s取得数字,应该是一样的,70s取得数据应该和前三次不一样。
这是使用C#自带缓存,还可以尝试试用一下 Redis
转自 https://www.jianshu.com/p/03e6741deb3c