【发布时间】:2011-03-09 11:56:33
【问题描述】:
您将如何使用 .Net 4 的新并发集合实现支持超时的缓存类?
缓存类通常包含数十万个条目。很大一部分缓存可能同时过期。
与可能因内存压力而缩小的典型 Web 缓存不同,此类应仅在对象超时时自动删除。
【问题讨论】:
标签: .net multithreading caching concurrency .net-4.0
您将如何使用 .Net 4 的新并发集合实现支持超时的缓存类?
缓存类通常包含数十万个条目。很大一部分缓存可能同时过期。
与可能因内存压力而缩小的典型 Web 缓存不同,此类应仅在对象超时时自动删除。
【问题讨论】:
标签: .net multithreading caching concurrency .net-4.0
为什么需要实现自定义缓存类?默认实现还不够吗?有一个whole new assembly dedicated to caching in .NET 4.0。缓存值 10 分钟的示例:
var cache = MemoryCache.Default;
cache.Add("key", new object(), DateTime.Now.AddMinutes(10));
【讨论】:
MemoryCache 将由于内存压力而被清除。
退后一步,考虑一下基于大小的缓存是如何工作的。 LRU 策略将删除最近使用的条目。当一个条目被访问(读取)或变异(写入)时,它被认为是被使用的。最常见的算法是让一个双向链表横切哈希表,以便表查找在 O(1) 时间内找到列表链中的条目。该列表保持顺序,其中头部是最近最少使用的,尾部是最近使用的,因此访问的条目被移动到尾部。在驱逐时,头部条目是受害者,它被取消链接并从表中删除。
现在考虑到期。实践中发现的策略会根据最后一次读取(time-to-idle)或最后一次写入(time-to-live)重置超时。这听起来可能类似于上面描述的 LRU 算法,因为它基于相同的访问模式维护排序。唯一的区别是缓存确定需要驱逐的时间:大小与时间。因此,我们可以应用相同的算法,只是改变我们检测溢出的方式!
这意味着您可以实现 LRU 算法并泛化评估谓词以允许在容量限制到时间限制之间切换。结果是时间和空间有效的过期缓存。
【讨论】:
ConcurrentLinkedHashMap 并喜欢阅读它。我明白您使用相同算法并进行一些调整的观点(例如避免维持最大重量)。尽管如此,您的代码在其核心中使用 Java 并发集合。至少,他们的 .Net 同行不适合这项工作。例如,删除一项 ConcurrentDictionary 会锁定其中一个锁条。 100,000 次删除将执行得非常糟糕,一次又一次地锁定相同的 Monitor 锁并花费大量时间。 (续...)