ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

背景:

1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了。

2:.NET Core 有新的Memory Cache提供,不过该内存类我看了一下,并没有支持文件的缓存依赖。

因此,在此前提下,预计.NET Core明年出来2.0版本时,可能也没支持文件的缓存依赖,因此,有必要提前准备实现。

在写此文前,我扫了一下园子里关于自定义缓存类的相关文章。

发现很多自定义的缓存类文章都简单停留在对字典的增删改查。

因此,决定补充这一篇完整思路的。

下面,就介绍一下这个缓存类的实现过程及原理。

实现缓存的类的核心思路介绍:

1:用static Dictionary<string,object> 来存档。

A:为了处理并发,V4.0或以上,可以用System.Collections.Concurrent.ConcurrentDictionary<string,object> 来存档。

B:如果为了支持.NET 2.0,则需要自己实现一个加锁的字典(本文即此种情况)

2:对该Dictionary提供增删改查方法。

3:提供定时缓存的过期策略。

4:提供文件监控策略。

5:测试并发、性能、和内存占用问题。

以下内容,重点介绍我的思路,源码截图以片断方式提供,具体的源码,会在链接中。

1:自定义线程安全的MDictionary(支持.NET 2.0)

如果要支持2.0,那么就只能自己实现了:实现的思路也很简单,只要对操作都加上锁即可:

详情源码见:https://github.com/cyq1162/cyqdata/blob/master/Tool/MDictionary.cs

2:时间过期策略:

 private MDictionary<string, object> theCache = new MDictionary<string, object>(2048, StringComparer.OrdinalIgnoreCase);//key,cache
 private MDictionary<string, DateTime> theKeyTime = new MDictionary<string, DateTime>(2048, StringComparer.OrdinalIgnoreCase);//key,time

有了theKeyTime,在每取get cache的时候,根据时间可以判断出,该Key是不是,如果已过期,则放弃。

但是有一个问题,如果缓存已经过期,但一直不被调用,那不是一直存在?

为了解决这个问题,需要一个定时器,定时清理过期的Cache。

由于Cache已经被设计成单例,因此可以在构造函数启动一个线程,来做定时任务清理过期的缓存。

下面有两种策略,以前的,和现在的,我分别介绍一下:

以前的:

定时遍历theKeyTime,找到过期时间的Cache进行删除。

因为遍历期间集合不能修改或删除,因此将遍历的符合条件的存档到新的对象,再统一处理新的对象去清除。

优点:逻辑简单。

缺点:遍历的过程,缓存不能被修改,需要锁住(缓存的对象越多,锁住的时间越长),另外每次都要遍历所有。

现在的:

private SortedDictionary<int, MList<string>> theTime = new SortedDictionary<int, MList<string>>();//worktime,keylist

新增加了一个时间片字典,以固定的时间(如5分钟)为1个单位。

这样所有缓存的时间就有序的分散在这些时间片上,定时器只要按节奏处理一个就可以了。

每个时间片都记录所有的Key。

缺点:增加处理逻辑。

优点:过期策略不再有锁,能快速直接定位过期数据并清除。

3:关于List的性能

【一开始我的思路是List<key> keys来存档所有key,移除的时候只移除key,然后其它交给定时器去清理。

由于只考虑它是线程安全,结果做性能测试时,很明显的发现问题】

List是链表实现,因此,随着数据量的增加,Contains方法的性能会极速下降。

因此,需要简单的处理一下解决性能问题,临时折腾了个MList:

 internal class MList<T>
    {
        List<T> list;
        Dictionary<T, int> dic;
        public MList()
        {
            list = new List<T>();
            dic = new Dictionary<T, int>();
        }
        public MList(int num)
        {
            list = new List<T>(num);
            dic = new Dictionary<T, int>(num);
        }
        public void Add(T key)
        {
            dic.Add(key, 0);
            list.Add(key);
        }
        public bool Contains(T key)
        {
            return dic.ContainsKey(key);
        }
        public void Remove(T key)
        {
            dic.Remove(key);
            list.Remove(key);
        }
        public void Clear()
        {
            dic.Clear();
            list.Clear();

        }
        public int Count
        {
            get
            {
                return list.Count;
            }
        }
        public List<T> GetList()
        {
            return list;
        }
    }

4:文件缓存依赖策略:

这个简而言之,就是文件被修改的时候,如何使缓存自动过期。

我要支持这个策略的原因:是因为Taurus.MVC,对View加载的html会被缓存在内存中的,当html被修改时,需要及时反应清掉缓存并重新加载。

 private MDictionary<string, string> theFileName = new MDictionary<string, string>();//key,filename

 private MDictionary<string, FileSystemWatcher> theFolderWatcher = new MDictionary<string, FileSystemWatcher>();//folderPath,watch
 private MDictionary<string, MList<string>> theFolderKeys = new MDictionary<string, MList<string>>();//folderPath,keylist

重点讲解:

1:用FileSystemWatcher来做文件监控(发现.NET Core里竟然有支持这个类)

2:问题:一开始,也是想的很简单,每一个文件开一个监控就完事了,结果没那么简单:

A:FileSystemWatcher对象太多,性能下降很快。

B:不同的Key指向同一个路径问题。

3:解决:后来,想到监控是以文件夹为单位,那么通过文件夹来搞搞实现:

A:以文件夹为单位:因此,文件对象即可以减少很多,提升性能问题。

B:以文件夹为单位:可以汇总对应的Keys,当文件变更时,可以快速定位到文件。

5:并发:

一个缓存类写好后,测试是少不了的,特别是并发,毕竟缓存是属于高并发的操作。

因此,缓存哪些地方要加lock的,哪些可以不加的,都需要仔细思考。

测试是通过的,就不截图了。

6:性能:

性能测试,是通过和HttpRuntime.Cache做的比较。

100万次的插入:

100万次的移除:

7:占用内存:

暂无测试。

详细源码:

https://github.com/cyq1162/cyqdata/blob/master/Cache/LocalCache.cs

总结:

本来是计划昨天就写此文的,结果临时开了培训课,因此只能深夜来写此文了。

关于培训见:http://www.cnblogs.com/cyq1162/p/6097445.html

在培训的过程,大伙都问怎么提升技术?我答:造轮子。

另外,有人问我怎么看.NET Core,还能怎么看,拉好板凳,就等你了:.NET Core 2.0。

夜又深深,该入眠了~~~~

时间: 2024-08-08 17:53:05

ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core的相关文章

ASP.NET HttpRuntime.Cache缓存类使用总结

1.高性能文件缓存key-value存储—Redis 2.高性能文件缓存key-value存储—Memcached 1.前言 a.在Web开发中,我们经常能够使用到缓存对象(Cache),在ASP.NET中提供了两种缓存对象,HttpContext.Current.Cache和HttpRuntime.Cache,那么他们有什么区别呢?下面简单描述一下: (1):HttpContext.Current.Cache 为当前Http请求获取Cache对象,通俗来说就是由于此缓存封装在了HttpCont

java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessController的checkPerssiom方法,访问控制器AccessController的栈检查机制又遍历整个 PerssiomCollection来判断具体拥有什么权限一旦发现栈中一个权限不允许的时候抛出异常否则简单的返回,这个过程实际上比我的描述要复杂 得多,这里我只是简单的一句带过,因为这

ASP.NET Core 开发-Logging 使用NLog 写日志文件

ASP.NET Core 开发-Logging 使用NLog 写日志文件. NLog 可以适用于 .NET Core 和 ASP.NET Core . ASP.NET Core已经内置了日志支持,可以轻松输出到控制台. 学习Logging 组件的相关使用,使用NLog 将日志写入到文件记录. Logging 使用 新建一个 ASP.NET Core 项目,为了方便,我选择Web 应用程序,改身份验证 改为 不进行身份验证. 新建好以后,会自动引用好对应的 类库.这样我们就可以直接使用 Logge

ASP.NET CORE系列【二】使用Entity Framework Core进行增删改查

原文:ASP.NET CORE系列[二]使用Entity Framework Core进行增删改查 介绍 EntityFrameworkCore EF core 是一个轻量级的,可扩展的EF的跨平台版本.对于EF而言 EF core 包含许多提升和新特性,同时 EF core 是一个全新的代码库,并不如 EF6 那么成熟和稳定.EF core 保持了和EF相似的开发体验,大多数顶级API都被保留了下来,所以,如果你用过EF6,那么上手EF core你会觉得非常轻松和熟悉,EF core 构建在一

Spring Batch学习笔记二

此系列博客皆为学习Spring Batch时的一些笔记: Spring Batch的架构 一个Batch Job是指一系列有序的Step的集合,它们作为预定义流程的一部分而被执行: Step代表一个自定义的工作单元,它是Job的主要构件块:每一个Step由三部分组成:ItemReader.ItemProcessor.ItemWriter:这三个部分将执行在每一条被处理的记录上,ItemReader读取每一条记录,然后传递给ItemProcessor处理,最后交给ItemWriter做持久化:It

iOS9-by-Tutorials-学习笔记二:App-Search

iOS9-by-Tutorials-学习笔记二:App-Search 本文版权归作者所有,如需转载请联系孟祥月 CSDN博客:http://blog.csdn.net/mengxiangyue 独立博客:http://mengxiangyue.com 本文为自己读书的一个总结,可能与原书有一定出入 iOS 9推出了搜索技术,能够让用户在Spotlight中搜索到APP内部的内容.苹果提供了三个APP Search API: * NSUserActivity * Core Spotlight *

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac

Emacs 笔记二

Emacs 笔记二 Table of Contents 1. 前言 2. emacs基本操作(常用快捷键) 3. emacs模式讲解 4. emacs缓冲区 5. org mode 5.1. 列表 5.2. 快键键 5.3. 内嵌元素(插入代码什么的) 5.4. 表格 1 前言 最近在学着写博客,发现MarkDown真乃神器,于是去找了很多markdown的工具,发现作业部落 最好的那个,而无意间又发现了org-mode火爆到极致 非常被人推崇,其实作业部落 已经是能很完美的满足我的需求了,但是