当前位置:  开发笔记 > 编程语言 > 正文

C#的对象缓存

如何解决《C#的对象缓存》经验,为你挑选了4个好方法。

我正在为一些文档格式做文档查看器.为了更容易,让我们说这是一个PDF查看器,一个桌面应用程序.该软件的一个要求是渲染速度.所以,现在,当用户滚动文档时,我正在为下一页缓存图像.

这是有效的,UI非常敏感,似乎应用程序几乎可以立即呈现页面......但代价是:内存使用量有时会达到600MB.我将它全部缓存在内存中.

现在,我知道,我可以缓存到磁盘,但是这样做总是明显变慢.我想要做的是实现一些缓存(LRU?),其中一些缓存页面(图像对象)在内存中,大多数都在磁盘上.

在我开始这个之前,框架中有什么东西或某些库可以为我做这个吗?这似乎是一个非常普遍的问题.(这是一个桌面应用程序,而不是ASP.NET)

或者,您对此问题有其他想法吗?



1> Sam Saffron..:

我写了一个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();
        }

    }
}


我认为最好在删除和删除方法中删除"最近最少使用"的项目,而不是在索引器中删除.每次我在缓存中访问某些内容时,我都不希望获得性能提升,因为当我只是访问时,我不关心缓存是否"满".但是,当我添加时,我绝对关心缓存是否已满,并且确实想要清除当时最近最少使用的项目.

2> rsbarro..:

对于.NET 4.0,您也可以使用MemoryCachefrom System.Runtime.Caching.

http://msdn.microsoft.com/en-us/library/system.runtime.caching.aspx



3> Anton Gogole..:

有模式和实践企业库(更具体地说,缓存应用程序块),但IMO往往过度设计并且过于复杂.



4> Dave Van den..:

.NET Framework始终能够保持对对象的弱引用.

基本上,弱引用是对运行时认为"不重要"的对象的引用,并且可以在任何时间点通过垃圾回收运行来删除.例如,这可用于缓存事物,但是你无法控制被收集的内容和不被收集的内容.

另一方面,它使用起来非常简单,它可能就是您所需要的.

戴夫

推荐阅读
围脖上的博博_771
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有