C# 缓存

源代码: https://git.oschina.net/zhaord/CacheDemo.git


介绍

缓存,在一定程度上,是可以提高程序性能的一个解决方案,比如,我们从数据库读数据,如果每次都从数据库读取的话,每次都需要进行 网络IO操作,需要等待网络数据返回,如果在60s内,有成千上百个访问进行同样的数据进行查询,将会更加耗时耗力……如果,我们将第一个访问者查询的数据,先保存起来,然后60s内,其他访问者均读取保存起来的数据,这样不需要再去重新查询数据库,减少一定的网络操作,所以说,缓存,一定程度上可以提高程序性能!
这里将介绍如何使用C# 中的MemoryCache 来实现内存缓存!


建立项目

用vs 新建 命令行程序,然后,引入 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();
        }
    }

在具体实现类内,维护一个 MemoryCache, 其他方法,均操作MemoryCache 进行缓存操作!
在具体的设置缓存项中,设置了,如果过期时间为空的话,则设置多久为访问超时,如果两则都为空的话,则设置 定时超时,这里默认为 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取得数据应该和前三次不一样。
运行结果如下:

图片.png

通过结果我们可以发现,前三次的取值是一样的,也就是说,缓存是生效的


总结

主要是通过memoryCache来实现缓存,以及简单的缓存用法!


qq:1260825783
源代码:https://git.oschina.net/zhaord/CacheDemo.git
转载注明:http://www.jianshu.com/p/03e6741deb3c

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,685评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,656评论 18 399
  • 源代码: https://git.oschina.net/zhaord/CacheDemo.git (分支:dev...
    诸葛_小亮阅读 1,097评论 0 5
  • 平时在移动端开发页面的过程中,总会遇到一些问题,主要是各手机webview样式显示效果不一致造成的。以下总结了一些...
    Simon王小白阅读 1,462评论 0 5
  • 问题目录: 1.员工绩效管理有什么作用? 2.员工绩效管理的原则是什么? 3.年度绩效管理与年度绩效考核的关系是什...
    gchr阅读 4,517评论 0 33