评价历史人物的方法,btbbt,森碟超萌助威
软件开发中最常用的模式之一是缓存,这是一个简单但非常有效的概念,想法是重用操作结果,执行繁重的操作时,我们会将结果保存在缓存容器中,下次我们需要该结果时,我们将从缓存容器中取出它,而不是再次执行繁重的操作。
例如,要获得某人的头像,您可能需要前往数据库。我们不会每次都执行那次查询,而是将结果保存在缓存中,每次需要时都将其从内存中删除。
缓存非常适合不经常更改的数据,甚至永远不会改变。不断变化的数据不适合缓存,如当前机器的时间不应缓存,否则您将得到错误的结果。
public class naivecache<t> { private static dictionary<object, t> _cache = new dictionary<object, t>(); public static t getorcreate(object key, func<t> createitem) { t cacheentry; if (!_cache.trygetvalue(key, out cacheentry)) { cacheentry = createitem(); _cache.add(key, cacheentry); } return cacheentry; } }
//用法
naivecache<string>.getorcreate("test", () => { return "test123"; });
这个简单的代码解决了一个关键问题,要获取test的值,只有第一个请求才会实际执行数据库操作,然后将数据保存在进程存储器中,以后有关test的请求都将从内存中提取,从而节省时间和资源。
但是,作为编程中的大多数事情,没有什么是如此简单。由于许多原因,上述解决方案并不好。首先,这种实现不是线程安全的,多个线程使用时可能会发生异常,除此之外,缓存的项目将永远留在内存中,这实际上非常糟糕。
例如:
list<task> t1 = new list<task>(); foreach (var item in list) { var a = task.run(() => { console.write($"{naivecache<string>.getorcreate(item, () => { return item.tostring(); })}"); }); t1.add(a); } try { task.waitall(t1.toarray()); } catch { }
运行结果7234859,运行 的数据丢失了
为了处理这些问题,缓存框架具有驱逐策略(即删除策略),这些是根据某些逻辑从缓存中删除项目的规则,常见的驱逐政策是:
现在我们知道了我们需要什么,让我们继续寻找更好的解决方案。
令我非常沮丧的是,作为博主,微软已经创建了一个很棒的缓存实现,这剥夺了我自己创建类似实现的乐趣,但至少我写这篇博文的工作较少。
我将向您展示microsoft的解决方案,如何有效地使用它,以及如何在某些情况下改进它。
微软有2个解决方案,2个不同的nuget包用于缓存,两者都很棒,根据微软的,更喜欢使用microsoft.extensions.caching.memory
因为它与asp更好地集成.net核心。它可以很到asp .net core的依赖注入机制中。
这是一个基本的例子microsoft.extensions.caching.memory
:
/// <summary> /// 利用微软的库写的缓存 /// </summary> /// <typeparam name="t"></typeparam> public class simplememoycache<t> { private static memorycache _cache = new memorycache(new memorycacheoptions()); public static t getorcreate(object key, func<t> createitem) { t cacheentry; if (!_cache.trygetvalue(key, out cacheentry)) { cacheentry = createitem(); _cache.set(key, cacheentry); } return cacheentry; } }
用法:
simplememoycache<string>.getorcreate("test", () => { return "test123"; });
这与我自己非常相似naivecache
,所以改变了什么?嗯,首先,这是一个线程安全的实现。您可以安全地从多个线程一次调用它。
/// <summary> /// 带有策略的缓存 /// </summary> /// <typeparam name="t"></typeparam> public class memorycachewithpolicy<t> { /// <summary> /// 增加设置缓存大小 /// </summary> private static memorycache _cache = new memorycache(new memorycacheoptions() { sizelimit = 1024 }); public static t getorcreate(object key, func<t> createitem) { t cacheentry; if (!_cache.trygetvalue(key, out cacheentry)) { cacheentry = createitem(); var cacheentryoptions = new memorycacheentryoptions() .setsize(1) .setpriority(cacheitempriority.high) //设置优先级 .setslidingexpiration(timespan.fromseconds(2)) //2s没有访问删除 .setabsoluteexpiration(timespan.fromseconds(10)); //10s过期 _cache.set(key, cacheentry, cacheentryoptions); } return cacheentry; } }
让我们分析一下新增内容:
sizelimit
加入了memorycacheoptions,
这会将基于大小的策略添加到缓存容器中。相反,我们需要在每个缓存条目上设置大小,在这种情况下,我们每次设置为1 setsize(1),
这意味着缓存限制为1024个项目。.setpriority(cacheitempriority.high)
。级别为low,normal,high和neverremove。setslidingexpiration(timespan.fromseconds(2))
添加了,将滑动到期时间设置为2秒,这意味着如果超过2秒内未访问某个项目,它将被删除。setabsoluteexpiration(timespan.fromseconds(10))
添加了,它将绝对到期时间设置为10秒,这意味着如果物品尚未在10秒内被驱逐。除了示例中的选项之外,您还可以设置一个registerpostevictioncallback
委托,当项目被驱逐时将调用该委托。
这是一个非常全面的功能集。它让你想知道是否还有其他东西要添加,实际上有几件事。
这个实现中有几个重要的缺失部分。
英文原文中有说明,但是觉得不太好,再次没有翻译。
英文原文地址:
代码与所写有所修改,但是大致意思一样,如果感兴趣,可以看看英文。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
Blazor server side 自家的一些开源的, 实用型项目的进度之 CEF客户端
.NET IoC模式依赖反转(DIP)、控制反转(Ioc)、依赖注入(DI)
vue+.netcore可支持业务代码扩展的开发框架 VOL.Vue 2.0版本发布
网友评论