缓存,在.Net系统开发中,经常使用到。如果,让你自己去实现,你会怎么做呢。

开始编码前思考:

1、肯定 是要 根据 key 去查询对应value,so 应该是List<KeyValuePair> 这类集合做缓存载体;

2、肯定是要全局公用,so 缓存的列表应该唯一;

3、应该有支持并发的能力,so 实现过程中肯定要加锁;

4、应该可以支持过期,自动 or 手动,so 应该 可以添加过期时间;

好的,基于以上3点,设计的类应该需要是单体(单例)模式,查询、删除key时应该lock 缓存载体,可以有定时清除过期缓存项的能力;

  1     public static class CacheHelper
  2     {
  3         private static int RestoreCacheCount = 20000;
  4         private static DateTime LastRestoreCachTime;
  5         private static Dictionary<string, MyCacheEntity> CacheEntryDictionary;
  6         private static readonly object objLock = new object();
  7
  8         static CacheHelper()
  9         {
 10             if (CacheEntryDictionary == null)
 11             {
 12                 lock (objLock)
 13                 {
 14                     if (CacheEntryDictionary == null)
 15                     {
 16                         CacheEntryDictionary = new Dictionary<string, MyCacheEntity>();
 17                         LastRestoreCachTime = DateTime.Now;
 18                         System.Threading.Tasks.Task.Factory.StartNew(() => RestoreCache());
 19                     }
 20                 }
 21             }
 22         }
 23
 24         public static void Set<T>(string key, T entity, double timeout)
 25         {
 26             if (string.IsNullOrEmpty(key))
 27                 throw new ArgumentNullException(nameof(key));
 28             if (entity == null)
 29                 throw new ArgumentNullException(nameof(entity));
 30             var expiredTime = DateTime.Now.AddSeconds(timeout);
 31             lock (objLock)
 32             {
 33                 if (DateTime.Now.Subtract(expiredTime).TotalSeconds >= 0)
 34                 {
 35                     if (CacheEntryDictionary.ContainsKey(key))
 36                         CacheEntryDictionary.Remove(key);
 37                 }
 38                 else
 39                 {
 40                     CacheEntryDictionary[key] = new MyCacheEntity { Value = entity, ExpiredTime = expiredTime };
 41                 }
 42             }
 43         }
 44
 45         public static T Get<T>(string key)
 46         {
 47             if (string.IsNullOrEmpty(key))
 48                 throw new ArgumentNullException(nameof(key));
 49             var value = default(T);
 50             lock (objLock)
 51             {
 52                 var exist = CacheEntryDictionary.ContainsKey(key);
 53                 if (!exist) return value;
 54                 var obj = CacheEntryDictionary[key];
 55                 if (obj == null)
 56                 {
 57                     CacheEntryDictionary.Remove(key);
 58                     return value;
 59                 }
 60                 if (obj.ExpiredTime == DateTime.MinValue || DateTime.Now.Subtract(obj.ExpiredTime).TotalSeconds >= 0)
 61                 {
 62                     CacheEntryDictionary.Remove(key);
 63                     return value;
 64                 }
 65                 return (T)Convert.ChangeType(obj.Value, typeof(T));
 66             }
 67         }
 68
 69         public static void Remove(string key)
 70         {
 71             if (string.IsNullOrEmpty(key))
 72                 throw new ArgumentNullException(nameof(key));
 73             try
 74             {
 75                 lock (objLock)
 76                 {
 77                     var exist = CacheEntryDictionary.ContainsKey(key);
 78                     if (!exist) return;
 79                     CacheEntryDictionary.Remove(key);
 80                 }
 81             }
 82             catch (Exception e)
 83             {
 84                 throw e;
 85             }
 86         }
 87
 88         public static void Clear()
 89         {
 90             try
 91             {
 92                 lock (objLock)
 93                 {
 94                     CacheEntryDictionary.Clear();
 95                     LastRestoreCachTime = DateTime.Now;
 96                 }
 97             }
 98             catch (Exception e)
 99             {
100                 throw e;
101             }
102         }
103
104         public static int Count => CacheEntryDictionary?.Count ?? 0;
105
106         private static void RestoreCache()
107         {
108             while (true)
109             {
110                 if (CacheEntryDictionary.Keys.Count < 1) return;
111                 try
112                 {
113                     bool isEnter = false;
114                     Monitor.TryEnter(CacheEntryDictionary, 1000, ref isEnter);
115                     if (isEnter)
116                     {
117                         if (CacheEntryDictionary.Count > RestoreCacheCount && DateTime.Now.Subtract(LastRestoreCachTime).TotalMinutes > 1)
118                         {
119                             var keys = CacheEntryDictionary.Where(m => m.Value.ExpiredTime < DateTime.Now).Select(m => m.Key).ToList();
120                             foreach (var key in keys)
121                             {
122                                 CacheEntryDictionary.Remove(key);
123                             }
124                             LastRestoreCachTime = DateTime.Now;
125                         }
126                     }
127                 }
128                 finally
129                 {
130                     Monitor.Exit(CacheEntryDictionary);
131                 }
132                 Thread.Sleep(1000 * 6);
133             }
134         }
135     }
136     public class MyCacheEntity
137     {
138         public object Value { get; set; }
139         public DateTime ExpiredTime { get; set; }
140     }

如果想要 key 不区分大小写,可以 在构造函数中 设置

CacheEntryDictionary = new Dictionary<string, MyCacheEntity>(StringComparer.OrdinalIgnoreCase);

你可能会有疑问,为什么不用 线程安全的字典 ConcurrentDictionary 呢?

当然可以将 Dictionary 改为 ConcurrentDictionary 没有任何问题,只是我想要自己手动实现加减速的过程;ConcurrentDictionary 字典内部也是调用Monitor 进行的加减锁的过程;

如果想要在缓存中实现 缓存文件,并且文件内容改变同步修改缓存的内容呢?

修改 以上方法 加入

1、添加缓存文件

2、刷新缓存文件内容,定时过期、监控文件内容更改等;

相关代码;

  1     public static class CacheHelper
  2     {
  3         private static int RestoreCacheCount = 20000;
  4         private static DateTime LastRestoreCachTime;
  5         private static Dictionary<string, MyCacheEntity> CacheEntryDictionary;
  6         private static readonly object objLock = new object();
  7         private static Dictionary<string, MyCacheEntity> FileCacheEntryDictionary;
  8
  9         static CacheHelper()
 10         {
 11             if (CacheEntryDictionary == null)
 12             {
 13                 lock (objLock)
 14                 {
 15                     if (CacheEntryDictionary == null)
 16                     {
 17                         CacheEntryDictionary = new Dictionary<string, MyCacheEntity>(StringComparer.OrdinalIgnoreCase);
 18                         LastRestoreCachTime = DateTime.Now;
 19                         System.Threading.Tasks.Task.Factory.StartNew(() => RestoreCache());
 20                     }
 21                     if (FileCacheEntryDictionary == null)
 22                     {
 23                         FileCacheEntryDictionary = new Dictionary<string, MyCacheEntity>();
 24                         System.Threading.Tasks.Task.Factory.StartNew(() => ReFreshFileCache());
 25                     }
 26                 }
 27             }
 28         }
 29
 30         public static void Set<T>(string key, T entity, double timeout)
 31         {
 32             if (string.IsNullOrEmpty(key))
 33                 throw new ArgumentNullException(nameof(key));
 34             if (entity == null)
 35                 throw new ArgumentNullException(nameof(entity));
 36             var expiredTime = DateTime.Now.AddSeconds(timeout);
 37             lock (objLock)
 38             {
 39                 if (DateTime.Now.Subtract(expiredTime).TotalSeconds >= 0)
 40                 {
 41                     if (CacheEntryDictionary.ContainsKey(key))
 42                         CacheEntryDictionary.Remove(key);
 43                 }
 44                 else
 45                 {
 46                     CacheEntryDictionary[key] = new MyCacheEntity { Value = entity, ExpiredTime = expiredTime };
 47                 }
 48             }
 49         }
 50
 51         public static void SetFile(string key, string filePath, Encoding encoding, double timeout)
 52         {
 53             if (string.IsNullOrEmpty(key))
 54                 throw new ArgumentNullException(nameof(key));
 55             if (!File.Exists(filePath))
 56                 throw new FileNotFoundException(filePath);
 57             var expiredTime = DateTime.Now.AddSeconds(timeout);
 58             lock (objLock)
 59             {
 60                 if (DateTime.Now.Subtract(expiredTime).TotalSeconds >= 0)
 61                 {
 62                     if (CacheEntryDictionary.ContainsKey(key))
 63                         CacheEntryDictionary.Remove(key);
 64                 }
 65                 else
 66                 {
 67                     FileInfo fileInfo = new FileInfo(filePath);
 68                     string value = null;
 69                     using (var stream = new StreamReader(filePath, encoding))
 70                     {
 71                         value = stream.ReadToEnd();
 72                     }
 73                     CacheEntryDictionary[key] = new MyCacheEntity
 74                     {
 75                         Value = value,
 76                         ExpiredTime = expiredTime
 77                     };
 78                     FileCacheEntryDictionary[key] = new MyCacheEntity
 79                     {
 80                         Value = new FileCacheOption
 81                         {
 82                             FilePath = filePath,
 83                             FileSize = fileInfo.Length,
 84                             LastWriteTime = fileInfo.LastWriteTime,
 85                             Encoding = encoding
 86                         },
 87                         ExpiredTime = expiredTime
 88                     };
 89                 }
 90             }
 91         }
 92
 93         public static T Get<T>(string key)
 94         {
 95             if (string.IsNullOrEmpty(key))
 96                 throw new ArgumentNullException(nameof(key));
 97             var value = default(T);
 98             lock (objLock)
 99             {
100                 var exist = CacheEntryDictionary.ContainsKey(key);
101                 if (!exist) return value;
102                 var obj = CacheEntryDictionary[key];
103                 if (obj == null)
104                 {
105                     CacheEntryDictionary.Remove(key);
106                     return value;
107                 }
108                 if (obj.ExpiredTime == DateTime.MinValue || DateTime.Now.Subtract(obj.ExpiredTime).TotalSeconds >= 0)
109                 {
110                     CacheEntryDictionary.Remove(key);
111                     return value;
112                 }
113                 return (T)Convert.ChangeType(obj.Value, typeof(T));
114             }
115         }
116
117         public static void Remove(string key)
118         {
119             if (string.IsNullOrEmpty(key))
120                 throw new ArgumentNullException(nameof(key));
121             try
122             {
123                 lock (objLock)
124                 {
125                     var exist = CacheEntryDictionary.ContainsKey(key);
126                     if (!exist) return;
127                     CacheEntryDictionary.Remove(key);
128                     if (FileCacheEntryDictionary.ContainsKey(key))
129                         FileCacheEntryDictionary.Remove(key);
130                 }
131             }
132             catch (Exception e)
133             {
134                 throw e;
135             }
136         }
137
138         public static void Clear()
139         {
140             try
141             {
142                 lock (objLock)
143                 {
144                     CacheEntryDictionary.Clear();
145                     FileCacheEntryDictionary.Clear();
146                     LastRestoreCachTime = DateTime.Now;
147                 }
148             }
149             catch (Exception e)
150             {
151                 throw e;
152             }
153         }
154
155         public static int Count => CacheEntryDictionary?.Count ?? 0;
156
157         private static void RestoreCache()
158         {
159             while (true)
160             {
161                 if (CacheEntryDictionary.Keys.Count < 1) return;
162                 try
163                 {
164                     bool isEnter = false;
165                     Monitor.TryEnter(CacheEntryDictionary, 1000, ref isEnter);
166                     if (isEnter)
167                     {
168                         if (CacheEntryDictionary.Count > RestoreCacheCount && DateTime.Now.Subtract(LastRestoreCachTime).TotalMinutes > 1)
169                         {
170                             var keys = CacheEntryDictionary.Where(m => m.Value.ExpiredTime < DateTime.Now).Select(m => m.Key).ToList();
171                             foreach (var key in keys)
172                             {
173                                 CacheEntryDictionary.Remove(key);
174                             }
175                             LastRestoreCachTime = DateTime.Now;
176                         }
177                     }
178                 }
179                 finally
180                 {
181                     Monitor.Exit(CacheEntryDictionary);
182                 }
183                 184                 Thread.Sleep(1000 * 6);
185             }
186         }
187
188         private static void ReFreshFileCache()
189         {
190             while (true)
191             {
192                 if (FileCacheEntryDictionary.Keys.Count < 1) return;
193                 try
194                 {
195                     bool isEnter = false;
196                     Monitor.TryEnter(FileCacheEntryDictionary, 100, ref isEnter);
197                     if (isEnter && FileCacheEntryDictionary.Keys.Count > 0)
198                     {
199                         var keys = FileCacheEntryDictionary.Keys.ToList();
200                         foreach (var key in keys)
201                         {
202                             var value = FileCacheEntryDictionary[key];
203                             if (value.ExpiredTime <= DateTime.Now)
204                             {
205                                 FileCacheEntryDictionary.Remove(key);
206                                 continue;
207                             }
208                             var fileCacheOption = value.Value as FileCacheOption;
209                             if (fileCacheOption == null)
210                             {
211                                 FileCacheEntryDictionary.Remove(key);
212                                 continue;
213                             }
214                             if (!File.Exists(fileCacheOption.FilePath))
215                             {
216                                 FileCacheEntryDictionary.Remove(key);
217                                 CacheEntryDictionary.Remove(key);
218                                 continue;
219                             }
220                             FileInfo fileInfo = new FileInfo(fileCacheOption.FilePath);
221                             if (fileInfo.Length != fileCacheOption.FileSize || fileInfo.LastWriteTime != fileCacheOption.LastWriteTime)
222                             {
223                                 fileCacheOption.LastWriteTime = fileInfo.LastWriteTime;
224                                 fileCacheOption.FileSize = fileInfo.Length;
225                                 FileCacheEntryDictionary[key] = new MyCacheEntity { Value = fileCacheOption, ExpiredTime = value.ExpiredTime };
226                                 using (var stream = new StreamReader(fileCacheOption.FilePath, fileCacheOption.Encoding))
227                                 {
228                                     Set(key, stream.ReadToEnd(), (int)value.ExpiredTime.Subtract(DateTime.Now).TotalSeconds);
229                                 }
230                             }
231                         }
232                     }
233                 }
234                 finally
235                 {
236                     Monitor.Exit(FileCacheEntryDictionary);
237                 }
238
239                 Thread.Sleep(100);
240             }
241         }
242     }
243     public class MyCacheEntity
244     {
245         public object Value { get; set; }
246         public DateTime ExpiredTime { get; set; }
247     }
248
249     public class FileCacheOption
250     {
251         public string FilePath { get; set; }
252         public long FileSize { get; set; }
253         public DateTime LastWriteTime { get; set; }
254         public Encoding Encoding { get; set; }
255     }

其实上边的文件监控 可以用 FileSystemWatcher 来做文件监控,。只是我做测试的时候,在触发多个事件读取文件内容时,会报文件被占用,然后就是在centos 下,编辑文件后保存时,会同时触发 Created、Changed 两个事件,在windows 下不存在这种情况,可能是我的方法设置有问题吧。

转载于:https://www.cnblogs.com/flyfishing/articles/Global_CacheHelper.html

关于全局缓存的一种简单实现方法相关推荐

  1. 有没有一种简单的方法可以按值删除列表元素?

    a = [1, 2, 3, 4] b = a.index(6)del a[b] print a 上面显示了以下错误: Traceback (most recent call last):File &q ...

  2. 一百种简单整人方法_一种非常简单的用户故事方法

    一百种简单整人方法 User stories are a great way to plan development work. In theory. But how do you avoid get ...

  3. java按两列输出_有没有一种简单的方法可以将两列输出到Java中的控制台? - java...

    如标题所述,是否有一种简单的方法可以将两列输出到Java中的控制台? 我知道\t,但是在使用printf时,我还没有找到基于特定列进行空间分配的方法. 参考方案 使用宽度和精度说明符,将其设置为相同的 ...

  4. 上微信怎么同时用计算机,电脑端微信双开,教你两种简单的方法,上手即用!...

    原标题:电脑端微信双开,教你两种简单的方法,上手即用! 微信现在已不单单是社交软件了,如今已成了工作必备软件,每天上班微信电脑端一登,传个文件,发个群通知,实在方便. 但是很多人都不止有一个微信号,电 ...

  5. 电脑端微信双开,教你两种简单的方法,上手即用!

    电脑端微信双开,教你两种简单的方法,上手即用! https://kuaibao.qq.com/s/20181117A0GAZF00?refer=spider 微信现在已不单单是社交软件了,如今已成了工 ...

  6. 9种简单的方法来使用社交媒体SEO

    9种简单的方法来使用社交媒体SEO 搜索引擎优化和社交媒体营销是两种策略,可以帮助提升品牌知名度并推广您的业务.他们创造吸引人的身份,自然吸引游客. 由于社交媒体主要依靠高质量的内容和强大的可见品牌存 ...

  7. python 加一个月 日期,有没有一种简单的方法可以在Python中将datetime对象增加一个月?...

    本问题已经有最佳答案,请猛点这里访问. 所以我试图找到一种方法,将日期时间对象增加一个月.然而,根据这个问题,这似乎不是那么简单. 我希望有这样的事情: import datetime as dt n ...

  8. android 层级边框,有没有一种简单的方法可以在Android视图的顶部和底部添加边框?...

    有没有一种简单的方法可以在Android视图的顶部和底部添加边框? 我有一个TextView,我想沿其顶部和底部边框添加黑色边框. 我尝试将android:drawableTop和android:dr ...

  9. 三角网格参数化几种简单的方法比较

    三角网格参数化可归结为这样一个问题:给定一个由空间点集组成的三角网格和一个二维参数域.通常为平面或者球面.求一个参数域上的点 P∗iP_i^* 到网格上的点pip_i的一一映射.使得参数域上的网格与原 ...

最新文章

  1. mysql 113_MySQL教程113-MySQL流程控制语句
  2. 我们和计算机系的老教授聊了聊TCP优化与产学矛盾
  3. Redis 的应用场景
  4. 链表之单链表的反转总结
  5. C++不定长字符串比较合理且简单的解决方法
  6. (转)OL2中设置鼠标的样式
  7. python 求 gamma 分布_python如何生成各种随机分布图
  8. JSON文件导入Unity3d中是空的的问题
  9. qt的opengl开发(qopenglwidget)(初始化,画线,平移,局部缩放)2d开发
  10. wpe修改充值_wpe实现网络游戏修改
  11. C++之struct
  12. 英语汉语对比学习:名词(一)
  13. Vue多个元素的过渡
  14. 电信光猫 中兴ZXHN F412破解
  15. CodeForces 964A Splits
  16. 什么是一对一电脑无人直播?
  17. wps英文参考文献怎么对齐_wps英文参考文献怎么对齐_【论文攻略】排版技巧——如何用 Word 编辑参考文献......
  18. jack分享的1-3开wifi 零火版本智能开关解决方案
  19. linux运行gpg软件,Linux实用工具之GPG
  20. NFTFi赛道版图概览

热门文章

  1. @builder注解_SpringBoot 整合SpringSecurity示例实现前后分离权限注解+JWT登录认证
  2. 自定义Mybatis框架
  3. 移动端设置html的字体尺寸,移动端开发元素及字体尺寸适配基础知识
  4. inkscape生成g代码_三点二. 量子对抗生成网络 (Quantum GAN)
  5. Pytorch代码函数笔记
  6. python获取一个月之前日期_利用python获取当前日期前后N天或N月日期的方法示例...
  7. 修改value_Python | 快速修改或命名N个文件夹名称,你会吗?
  8. aes子密钥生成c语言_一种基于流密码算法的子密钥生成方法与流程
  9. visual2019没有勾选的在如何加入_发票管理系统完成升级,勾选认证平台改头换面,你所有的问题都在这里!...
  10. C语言代码注释必须用/**/ , 你没看错~