我希望使用System.Runtime.Caching名称空间将缓存功能添加到我的应用程序中,并且可能希望在多个位置和不同的上下文中使用缓存. 为此,我希望使用几个MemoryCache实例.

但是,我看到here不鼓励使用多个MemoryCache实例:

MemoryCache不是单例的,但是您应该只创建几个或可能只创建一个MemoryCache实例,并且缓存项目的代码应该使用这些实例.

多个MemoryCache实例将如何影响我的应用程序? 我觉得这有点奇怪,因为在我看来,在一个应用程序中使用多个缓存是一种非常常见的场景.

EDIT:更具体地说,我有一个类应该 for each 实例保存一个缓存.我应该避免使用MemoryCache,而寻找不同的缓存解决方案吗?在这种情况下使用MemoryCache被认为是不好的吗?如果是,为什么?

推荐答案

最近我自己也经历了这件事.考虑到内存中的缓存将是特定于进程的(不会在网站的多个实例或本地业务应用程序或多个服务器之间共享),除了代码组织原因(可以通过其他方式实现)外,拥有多个MemoryCache个实例实际上没有任何好处.

内存缓存主要用于单独使用,因为它具有内存管理功能.除了性能计数器(确实有一些开销)外,当内存缓存耗尽分配的内存时,它还能够使项过期.

如果缓存的当前实例超过了内存集的限制

MemoryCache.CacheMemoryLimit Property

通过只使用MemoryCache的一个实例,它可以在整个应用程序实例中有效地应用这种内存管理.使整个应用程序中最不重要的项过期.这确保了最大限度地使用内存,而不会超出硬件能力.通过限制任何一个MemoryCache的范围(比如一个类的一个实例),它无法再有效地管理应用程序的内存(因为它无法"看到"所有内容).如果所有这些缓存都处于"繁忙"状态,那么管理内存的难度可能会更大,而且它的效率也永远不会这么高.

这在没有专用服务器的应用程序中尤其敏感.假设你在一个共享服务器上运行应用程序,在这个服务器上你只分配了150mb内存(普通廉价的每月10美元托管),你需要依靠缓存最大限度地使用它,而不超过它.如果超过此内存使用量,你的应用程序池将被回收,你的应用程序将丢失所有内存缓存!(常见的廉价托管做法)这同样适用于内部托管在某个共享公司服务器上的非web应用程序.同样的交易,你被告知不要占用那台机器上的所有内存,并与其他业务应用和平共处.

内存限制、应用程序池回收、丢失缓存是web应用程序的常见"致命弱点".当应用程序最忙时,由于内存分配过多、丢失所有缓存项,它们重置的频率最高,因此在重新获取本来应该缓存的内容时所做的工作最多.这意味着应用程序实际上会在最大负载下失go 性能,而不是获得性能.

我知道MemoryCache是System.Web.Caching.Cache实现的非web特定版本,但这说明了缓存实现背后的逻辑.如果您没有对硬件的独占使用,同样的逻辑也可以应用于非Web项目.请记住,如果您的缓存强制机器开始执行页面文件交换,那么您的缓存不再比磁盘上的缓存快.您总是希望在某个地方设置一个限制,即使该限制是2 GB或更高.

在我的 case 中,在阅读了相关内容后,我在应用程序中改用了一个"公共静电内存缓存",并简单地按照缓存项的缓存键来分隔缓存项.例如,如果您想在每个实例上缓存,您可以有一个类似于"instance-{instanceId}-resourceName-{resourceId}".的缓存键可以将其视为缓存条目的名称间隔.

希望有帮助!

.net相关问答推荐

仅在有换行符时捕获分隔符之间的所有文本

类似于字典但没有值的 C# 数据 struct

"投掷;" 是什么意思?靠自己做什么?

如何获取 Sql Server 数据库中所有模式的列表

发布版本中的 Debug.WriteLine

File.ReadAllLines() 和 File.ReadAllText() 有什么区别?

C#:内存不足异常

.Net 中的 Int128?

无法将文件 *.mdf 作为数据库附加

双倍的? = 双倍? + 双倍?

如何使用 c# 仅获取目录中的文件名?

有没有办法从方法返回匿名类型?

文件按文件名模式存在

如何在 C# 中以编程方式安装 Windows 服务?

ConcurrentDictionary TryRemove 何时返回 false

DLL 中有什么以及它是如何工作的?

.NET 委托类型的正确命名约定?

为什么 .NET 中没有 Tree 类?

泛型类的默认构造函数的语法是什么?

ConfigurationManager.AppSettings - 如何修改和保存?