C# 缓存

作者: 诸葛_小亮 | 来源:发表于2016-12-10 22:27 被阅读704次

    源代码: https://git.oschina.net/zhaord/CacheDemo.git


    介绍

    缓存,在一定程度上,是可以提高程序性能的一个解决方案,比如,我们从数据库读数据,如果每次都从数据库读取的话,每次都需要进行 网络IO操作,需要等待网络数据返回,如果在60s内,有成千上百个访问进行同样的数据进行查询,将会更加耗时耗力……如果,我们将第一个访问者查询的数据,先保存起来,然后60s内,其他访问者均读取保存起来的数据,这样不需要再去重新查询数据库,减少一定的网络操作,所以说,缓存,一定程度上可以提高程序性能!
    这里将介绍如何使用C# 中的MemoryCache 来实现内存缓存!


    建立项目

    用vs 新建 命令行程序,然后,引入 system.running.cache类库


    Cache 实现

    定义一个ICache 接口

    
        public interface ICache
        {
            /// <summary>
            ///     获取缓存项,当没有缓存时,使用factory提供的值
            /// </summary>
            /// <param name="key"></param>
            /// <param name="factory"></param>
            /// <returns></returns>
            object Get(string key, Func<string, object> factory);
    
    
            /// <summary>
            ///     获取缓存项,没有缓存时返回默认数据
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            object GetOrDefault(string key);
    
            /// <summary>
            ///     设置缓存项并设置过期时间
            /// </summary>
            /// <param name="key">key</param>
            /// <param name="value">值</param>
            /// <param name="slidingExpireTime">多久未访问则失效</param>
            /// <param name="absoluteExpireTime">超时失效</param>
            void Set(string key, object value, TimeSpan? slidingExpireTime = null,TimeSpan?absoluteExpireTime=null);
    
            /// <summary>
            ///     移除缓存项
            /// </summary>
            /// <param name="key"></param>
            void Remove(string key);
    
            /// <summary>
            ///     清空缓存
            /// </summary>
            void Clear();
    
        }
    

    该接口提供了获取缓存、设置缓存、移除缓存和清空缓存操作,且 get 方法,如果缓存中没有项,则可以通过 factory返回数据并保存到缓存!
    缓存基类:CacheBase

        public abstract class CacheBase : ICache
        {
    
            protected readonly object SyncObj = new object();
    
            protected CacheBase()
            {
            }
    
            public virtual object Get(string key, Func<string, object> factory)
            {
                var cacheKey = key;
                var item = this.GetOrDefault(key);
                if (item == null)
                {
                    lock (this.SyncObj)// TODO: 为何要锁定
                    {
                        item = this.GetOrDefault(key);
                        if (item != null)
                        {
                            return item;
                        }
    
                        item = factory(key);
                        if (item == null)
                        {
                            return null;
                        }
    
                        this.Set(cacheKey, item);
                    }
                }
    
                return item;
            }
            
            public abstract object GetOrDefault(string key);
            
            public abstract void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
            
            public abstract void Remove(string key);
            
            public abstract void Clear();
            
            public virtual void Dispose()
            {
    
            }
        }
    
    

    缓存基类为虚类,只实现了 Get(string key, Func<string, object> factory) 方法, 这里进行了锁定,主要是为了多线程操作,在设置缓存的时候,只会有一个访问者在设置缓存项,其他方法均为虚方法,等待具体实现类实现

    缓存具体实现类:DemoCache

        public class DemoCache : CacheBase
        {
            private MemoryCache _memoryCache;
    
            public DemoCache()
                : base()
            {
                this._memoryCache = new MemoryCache("DemoCache");
            }
            
            public override object GetOrDefault(string key)
            {
                return this._memoryCache.Get(key);
    
            }
    
            public override void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
            {
                if (value == null)
                {
                    throw new Exception("Can not insert null values to the cache!");
                }
    
    
                var cachePolicy = new CacheItemPolicy();
    
                if (absoluteExpireTime != null)
                {
                    cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.Add(absoluteExpireTime.Value);
    
                }
                else if (slidingExpireTime != null)
                {
                    cachePolicy.SlidingExpiration = slidingExpireTime.Value;
                }
                else
                {
                    cachePolicy.AbsoluteExpiration = DateTimeOffset.Now.Add(TimeSpan.FromSeconds(60));
                    
    
                }
    
                this._memoryCache.Set(key, value, cachePolicy);
    
            }
    
            public override void Remove(string key)
            {
                this._memoryCache.Remove(key);
    
            }
    
            public override void Clear()
            {
                // 将原来的释放,并新建一个cache
                this._memoryCache.Dispose();
                this._memoryCache = new MemoryCache("DemoCache");
    
            }
            
            public override void Dispose()
            {
                this._memoryCache.Dispose();
                base.Dispose();
            }
        }
    
    

    在具体实现类内,维护一个 MemoryCache, 其他方法,均操作MemoryCache 进行缓存操作!
    在具体的设置缓存项中,设置了,如果过期时间为空的话,则设置多久为访问超时,如果两则都为空的话,则设置 定时超时,这里默认为 60 秒。
    清空缓存的时候,则释放 memorycache,并新建具体cache实例来实现


    使用缓存

    定义一个方法,用来取数据

    private static int GetCacheRandom(ICache cache)
            {
                var cacheItem = cache.Get("random",
                    (key) =>
                    {
                        Random random = new Random();
                        return random.Next(1, 1000);
                    });
                return int.Parse(cacheItem.ToString());
            }
    
    

    这个方法,提供了取1到1000的随机值,并保存到缓存中。
    定义一个现实函数,用来现实 何时取到的数字

    
            private static void ShowCacheItem(int value)
            {
                Console.WriteLine("{0}  取数:{1}",DateTime.Now.ToString("HH:mm:ss"), value);
            }
    
    

    具体使用

    
    
            static void Main(string[] args)
            {
                ICache cache = new DemoCache();
    
                var cacheItem = GetCacheRandom(cache);
                Console.Write("第一次取值    ");
                ShowCacheItem(cacheItem);
    
                Stopwatch watch=new Stopwatch();
                watch.Start();
    
                while (true)
                {
                    if (watch.ElapsedMilliseconds < 10000)
                    {
                        continue;
                    }
    
                    cacheItem = GetCacheRandom(cache);
                    Console.Write("10s后取值    ");
                    ShowCacheItem(cacheItem);
                    break;
                }
    
                while (true)
                {
                    if (watch.ElapsedMilliseconds < 40000)
                    {
                        continue;
                    }
                    cacheItem = GetCacheRandom(cache);
                    Console.Write("40s后取值    ");
                    ShowCacheItem(cacheItem);
                    break;
                }
    
                while (true)
                {
                    if (watch.ElapsedMilliseconds < 70000)
                    {
                        continue;
                    }
                    cacheItem = GetCacheRandom(cache);
                    Console.Write("70s后取值,此时应该是新值    ");
                    ShowCacheItem(cacheItem);
                    break;
                }
                
                watch.Stop();
    
                Console.WriteLine("输入任意键退出!");
                Console.ReadKey();
    
            }
    
    
    

    首先建立 DemoCache的实例,然后获取一次数值,然后10s取一次数据,40s取一次数据,70s取一次数据,如果缓存生效,则前三次,即第一次,10s取得一次,40s取得数字,应该是一样的,70s取得数据应该和前三次不一样。
    运行结果如下:

    图片.png

    通过结果我们可以发现,前三次的取值是一样的,也就是说,缓存是生效的


    总结

    主要是通过memoryCache来实现缓存,以及简单的缓存用法!


    qq:1260825783
    源代码:https://git.oschina.net/zhaord/CacheDemo.git
    转载注明:http://www.jianshu.com/p/03e6741deb3c

    相关文章

      网友评论

        本文标题:C# 缓存

        本文链接:https://www.haomeiwen.com/subject/rypumttx.html