当前位置 博文首页 > 陈大宝:C#中普通缓存的使用

    陈大宝:C#中普通缓存的使用

    作者:陈大宝 时间:2021-05-05 18:17

    缓存的概念及优缺点在这里就不多做介绍,当然缓存包含多种有普通缓存、客户端缓存、DNS缓存、反向代理缓存以及分布式缓存等等。今天主要聊一聊C#通过编码来实现普通的缓存、话不多说直接上代码。

     

    一、首先,新建控制台程序(.NET Core)、以下为项目结构

     

     

    1. CacheHelper缓存帮助类
    2. DemoTest 为测试有无缓存的Demo代码
    3. Program 你们懂得 就不多说了

    二、编写缓存类

     

     public class CacheHelper
        {
            //缓存容器 
            private static Dictionary<string, object> CacheDictionary = new Dictionary<string, object>();
            /// <summary>
            /// 添加缓存
            /// </summary>
            public static void Add(string key, object value)
            {
                CacheDictionary.Add(key, value);
            }
    
            /// <summary>
            /// 获取缓存
            /// </summary>
            public static T Get <T>(string key)
            {
                return (T)CacheDictionary[key];
            }
    
    
            /// <summary>
            /// 缓存获取方法
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key">缓存字典容器对应key</param>
            /// <param name="func">委托方法 传入操作对象</param>
            /// <returns></returns>
            public static T GetCache<T>(string key, Func<T> func)
            {
                T t = default(T);
                if (CacheHelper.Exsits(key))
                {
                    //缓存存在,直接获取原数据
                    t = CacheHelper.Get<T>(key);
                }
                else
                {
                    //缓存不存在,去生成缓存,并加入容器
                    t = func.Invoke();
                    CacheHelper.Add(key, t);
                }
                return t;
            }
    
            /// <summary>
            /// 判断缓存是否存在
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static bool Exsits(string key)
            {
                return CacheDictionary.ContainsKey(key);
            }
    public static T GetCache<T>(string key, Func<T> func)我这里直接使用泛型委托封装了缓存的方法了。当然你也可以不封装直接使用if else 判断
    if (CacheHelper.Exsits(key)){} else{}
    但是实际开发使用缓存应该不是一个地方使用缓存、频繁的使用if else 判断代码有点冗余、所有我就使用采用泛型委托方式封装方法 这个大家可以自行选择

      以上一般采用静态字典添加缓存数据、为了有更好的兼容性我这里直接采用泛型(泛型的好处这里就不多说了、总之性能相对更好、能够提高代码的重用性)

    二、编写有缓存和没有缓存方法

     

        public class DemoTest
        {
            /// <summary>
            /// 使用缓存测试
            /// </summary>
            /// <param name="count"></param>
            /// <returns></returns>
            public static List<People> CacheTest(int count)
            {
                People people = new People();
    
    
                List<People> ListPeople = new List<People>();
                for (int i = count; i < 100000; i++)
                {
                    Console.WriteLine($"------第{i}次请求------");
                    //int result = DataSource.GetDataByDB(666);
    
                    //key的名字一定要确保请求的准确性 DataSource GetDataByDB 666缺一不可
                    string key = "DataSource_GetDataByDB_666";
                    ListPeople = CacheHelper.GetCache(key, () => DemoTest.GetListData());
                    Console.WriteLine($"第{i}次请求获得的数据为:{people}");
               
                }
                return ListPeople;
            }
    
            /// <summary>
            /// 没有使用缓存
            /// </summary>
            /// <param name="count"></param>
            /// <returns></returns>
            public static List<People> NoCacheTest(int count)
            {
                People people = new People();
    
    
                List<People> ListPeople = new List<People>();
                for (int i = count; i < 100000; i++)
                {
                    Console.WriteLine($"------第{i}次请求------");
                    //int result = DataSource.GetDataByDB(666);
    
                    //key的名字一定要确保请求的准确性 DataSource GetDataByDB 666缺一不可
                    string key = "DataSource_GetDataByDB_666";
    
                    //if (CacheHelper.Exsits(key))
                    //{
                    //    //缓存存在,直接获取原数据
                    //    result = CacheHelper.Get<int>(key);
                    //}
                    //else
                    //{
                    //    //缓存不存在,去生成缓存,并加入容器
                    //    result = 78;
                    //    CacheHelper.Add(key, result);
                    //}
                    ListPeople = GetListData();
                    Console.WriteLine($"第{i}次请求获得的数据为:{people}");
                }
                return ListPeople;
    
            }
    
            /// <summary>
            /// 读取数据源 这里模拟数据源读取 循环3000
            /// </summary>
            /// <returns></returns>
            public static List<People> GetListData()
            {
                List<People> peoplesList = new List<People>();
    
    
                for (int i = 0; i < 3000; i++)
                {
                    People people = new People()
                    {
                        Age = i,
                        Name = "陈大宝" + i.ToString()
                    };
    
                    peoplesList.Add(people);
                }return peoplesList;
            }
        }

     

     

     

     三、控制台上端调用

        class Program
        {
            static void Main(string[] args)
            {
    
                {
                    Console.WriteLine("******************缓存测试****************");
                    Stopwatch stopwatch = new Stopwatch();
                    stopwatch.Start();
    
                    var iResulr = DemoTest.CacheTest(0);
    
                    stopwatch.Stop();
    
                    Console.WriteLine("有缓存消耗时间为" + stopwatch.ElapsedMilliseconds);
                }
                {
                    Console.WriteLine("*****************没有缓存测试****************");
                    Stopwatch stopwatch = new Stopwatch();
                    stopwatch.Start();
    
                    var iResulr = DemoTest.NoCacheTest(0);
    
                    stopwatch.Stop();
    
                    Console.WriteLine("没有缓存消耗时间为" + stopwatch.ElapsedMilliseconds);
                }
            }
        }

    一、循环10万次有缓存消耗时间

       二、循环10万次没有有缓存消耗时间

      

      以上为循环10万次验证后分析:以上消耗时间为毫秒、有缓存 22282毫秒大致为0.37分钟左右。没有缓存 82417毫秒大致为1.37分钟左右、两者相差1分钟左右、那么有朋友可能会发现你这也没快多少啊、但是兄弟们实际我们在访问时一分钟已经是相当久了、你能想象调用一次接口访问时间如果超过一分钟是什么感觉?那毫无疑问肯定得炸毛、而且我们访问数据实际第一次肯定是要到关系型数据中获取数据的、如果使用缓存直接第二次直接取内存缓存(不用去再去操作数据库IO了)、但是不使用缓存每次去操作数据库、当用户量稍微多一点数据库它是有性能开销越来越大、所以缓存是非常有效的、也是我们最能直观立竿见影的效果。

       

    总结一下哈:到这里,缓存的使用基本结束了。最好值得一提的是,缓存尽量在数据量小、重复查询量大的情况下使用。因为缓存也是要耗内存的,毕竟我们服务器内存是有限的!、当然了会有小伙伴会说我们都已经用Redis等等、确实现在缓存当然用的比较多是Redis了、Redis好处这里就不先谈了、总之本次文章是让没有了解普通缓存是如何使用得的小伙伴熟悉并了解、其实在这种方式在有些场景也是有它的好处的。

     

    bk