我正在为一些文档格式做文档查看器.为了更容易,让我们说这是一个PDF查看器,一个桌面应用程序.该软件的一个要求是渲染速度.所以,现在,当用户滚动文档时,我正在为下一页缓存图像.
这是有效的,UI非常敏感,似乎应用程序几乎可以立即呈现页面......但代价是:内存使用量有时会达到600MB.我将它全部缓存在内存中.
现在,我知道,我可以缓存到磁盘,但是这样做总是明显变慢.我想要做的是实现一些缓存(LRU?),其中一些缓存页面(图像对象)在内存中,大多数都在磁盘上.
在我开始这个之前,框架中有什么东西或某些库可以为我做这个吗?这似乎是一个非常普遍的问题.(这是一个桌面应用程序,而不是ASP.NET)
或者,您对此问题有其他想法吗?
我写了一个LRU Cache和一些测试用例,随意使用它.
您可以在我的博客上阅读来源.
对于懒惰(这里是减去测试用例):
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LRUCache { public class IndexedLinkedList{ LinkedList data = new LinkedList (); Dictionary > index = new Dictionary >(); public void Add(T value) { index[value] = data.AddLast(value); } public void RemoveFirst() { index.Remove(data.First.Value); data.RemoveFirst(); } public void Remove(T value) { LinkedListNode node; if (index.TryGetValue(value, out node)) { data.Remove(node); index.Remove(value); } } public int Count { get { return data.Count; } } public void Clear() { data.Clear(); index.Clear(); } public T First { get { return data.First.Value; } } } }
LRUCache
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LRUCache { public class LRUCache: IDictionary { object sync = new object(); Dictionary data; IndexedLinkedList lruList = new IndexedLinkedList (); ICollection > dataAsCollection; int capacity; public LRUCache(int capacity) { if (capacity <= 0) { throw new ArgumentException("capacity should always be bigger than 0"); } data = new Dictionary (capacity); dataAsCollection = data; this.capacity = capacity; } public void Add(TKey key, TValue value) { if (!ContainsKey(key)) { this[key] = value; } else { throw new ArgumentException("An attempt was made to insert a duplicate key in the cache."); } } public bool ContainsKey(TKey key) { return data.ContainsKey(key); } public ICollection Keys { get { return data.Keys; } } public bool Remove(TKey key) { bool existed = data.Remove(key); lruList.Remove(key); return existed; } public bool TryGetValue(TKey key, out TValue value) { return data.TryGetValue(key, out value); } public ICollection Values { get { return data.Values; } } public TValue this[TKey key] { get { var value = data[key]; lruList.Remove(key); lruList.Add(key); return value; } set { data[key] = value; lruList.Remove(key); lruList.Add(key); if (data.Count > capacity) { data.Remove(lruList.First); lruList.RemoveFirst(); } } } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public void Clear() { data.Clear(); lruList.Clear(); } public bool Contains(KeyValuePair item) { return dataAsCollection.Contains(item); } public void CopyTo(KeyValuePair [] array, int arrayIndex) { dataAsCollection.CopyTo(array, arrayIndex); } public int Count { get { return data.Count; } } public bool IsReadOnly { get { return false; } } public bool Remove(KeyValuePair item) { bool removed = dataAsCollection.Remove(item); if (removed) { lruList.Remove(item.Key); } return removed; } public IEnumerator > GetEnumerator() { return dataAsCollection.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)data).GetEnumerator(); } } }
对于.NET 4.0,您也可以使用MemoryCache
from System.Runtime.Caching
.
http://msdn.microsoft.com/en-us/library/system.runtime.caching.aspx
有模式和实践企业库(更具体地说,缓存应用程序块),但IMO往往过度设计并且过于复杂.
.NET Framework始终能够保持对对象的弱引用.
基本上,弱引用是对运行时认为"不重要"的对象的引用,并且可以在任何时间点通过垃圾回收运行来删除.例如,这可用于缓存事物,但是你无法控制被收集的内容和不被收集的内容.
另一方面,它使用起来非常简单,它可能就是您所需要的.
戴夫