C#:如何实现智能缓存

我有一些地方可以实现某种缓存。 例如,在基于自定义字符串执行资源查找,使用reflection查找属性名称或每个属性名称只有一个PropertyChangedEventArgs

最后一个简单的例子:

 public static class Cache { private static Dictionary cache; static Cache() { cache = new Dictionary(); } public static PropertyChangedEventArgs GetPropertyChangedEventArgs( string propertyName) { if (cache.ContainsKey(propertyName)) return cache[propertyName]; return cache[propertyName] = new PropertyChangedEventArgs(propertyName); } } 

但是,这会运作良好吗? 例如,如果我们有一大堆不同的propertyNames,那就意味着我们最终会有一个巨大的缓存,从来没有垃圾收集或任何东西。 我在想如果缓存的内容是更大的值,如果应用程序是一个长期运行的应用程序,这可能最终会成为一个问题……或者你怎么看? 如何实现好的缓存? 对于大多数用途,这个是否足够好? 一些很好的缓存实现的例子,这些实现不是很难理解,也不太复杂而无法实现?

您可以将每个缓存的项目包装在WeakReference 。 这将允许GC在需要时回收项目,但是它不会对项目何时从缓存中消失进行任何细粒度控制,或者允许您实现明确的过期策略等。

(哈!我刚注意到MSDN页面上给出的示例是一个简单的缓存类。)

这是一个大问题,您需要确定问题的域并应用正确的技术。 例如,您如何描述对象的到期? 它们会在固定的时间间隔内变得陈旧吗? 它们是否因外部事件而变得陈旧? 这种情况多久发生一次? 另外,你有多少个物品? 最后,生成对象需要多少钱?

最简单的策略是直接进行记忆,如上所述。 这假设对象永远不会过期,并且没有太多的内存干燥运行并且您认为创建这些对象的成本保证了开始使用缓存。

下一层可能是限制对象的数量,并使用隐式过期策略,例如LRU(最近最少使用)。 要做到这一点,除了字典之外,通常还会使用双向链表,每次访问对象时,它都会移动到列表的前面。 然后,如果您需要添加一个新对象,但它超过了总对象的限制,您将从列表的后面删除。

接下来,您可能需要根据时间或某些外部刺激强制显式到期。 这将要求您具有可以调用的某种到期事件。

正如您所看到的,缓存中有很多设计,因此您需要正确理解您的域和工程师。 我觉得你没有提供足够的细节来讨论具体细节。

PS请在定义类时考虑使用generics,以便可以存储许多类型的对象,从而允许重用高速缓存代码。

看起来.NET 4.0现在支持System.Runtime.Caching来缓存许多类型的东西。 你应该先研究一下,而不是重新发明轮子。 更多细节:

http://msdn.microsoft.com/en-us/library/system.runtime.caching%28VS.100%29.aspx

这是一个很好的辩论,但根据您的应用,这里有一些提示:

您应该定义缓存的最大大小,如果缓存已满,如何处理旧项目,具有清理策略,确定缓存中对象的生存时间,缓存是否/必须在其他位置持久保存内存,如果应用程序exception终止,…

这是一个常见问题,根据您的应用需求,有许多解决方案。 微软发布了一个完整的库来解决它是如此常见。 在汇总自己的缓存之前,您应该查看Microsoft Velocity。 http://msdn.microsoft.com/en-us/data/cc655792.aspx希望这个帮助。

您可以使用WeakReference但是如果您的对象不是那么大,因为WeakReference将占用比对象本身更多的内存,这不是一个好技术。 此外,如果对象是短时间使用,它将永远不会从GC的第0代进入第1代,则不需要WeakReference但对象上的IDisposable接口将与SuppressFinalize上的版本一起使用。

如果要控制生命周期,则需要一个计时器来再次更新日期时间/时间跨度缓存中对象的desiredExpirationTime。

重要的是如果对象很大,那么选择WeakReference,否则使用强引用。 此外,您可以在Dictionary上设置容量,并创建一个队列,用于请求临时bin中的其他对象序列化对象,并在Dictionary中有空间时加载它,然后从temp目录中清除它。