缓存

using Common;
using Microsoft.Extensions.Caching.Memory;
using MyBll;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MyCache
{
    class Program
    {
        static void Main(string[] args)
        {

            //缓存用在哪里?满足哪些特点适合用缓存?
            //访问频繁+耗时耗资源+相对稳定+体积不太大
            //也看业务需要,一般大型项目存一次缓存三个请求都用上了,就可以用
            //省市区/配置文件/网站公告/部门/权限/热搜/产品列表/用户信息

            //现在一般使用微软自带的缓存类,MemoryCache 这个时线程安全的
            //.net framework 引用using System.Runtime.Caching;
            //.net core 引用using Microsoft.Extensions.Caching.Memory;
            //core的这个类的方法好像没有Add(不知道怎么用)  使用方式和framework版本的不一样

            
            #region 缓存的应用
            1.缓存是优化系统的第一步

            浏览器(客户端缓存)--DNS解析(CDN)--反向代理(反向代理缓存)--服务器--(本地缓存[内存]、分布式缓存)--数据库


            1 重复请求,比如100个人访问首页,每个请求的返回其实都一样
            2 耗时耗资源
            3 结果没变
            此时应该缓存下来提升性能
            //for (int i = 0; i < 5; i++)
            //{
            //    Console.WriteLine($"获取{nameof(DbHelper)} {i}次 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");

            //    //存取数据的唯一标识
            //    //1 唯一性;        2 能重现,取的时候还要用呢
            //    string key = $"{nameof(DbHelper)}_Query_{123}";

            //    List<Program> programList = CustomCache.GetValue<List<Program>>(key, () => DbHelper.Query<Program>(123));
            //    //if (!CustomCache.Exists(key))
            //    //{
            //    //    programList = DbHelper.Query<Program>(123);
            //    //    CustomCache.Add(key, programList);
            //    //}
            //    //else
            //    //{
            //    //    programList = CustomCache.GetT<List<Program>>(key);
            //    //}
            //}

            //for (int i = 0; i < 5; i++)
            //{
            //    Console.WriteLine($"获取{nameof(FileHelper)} {i}次 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");

            //    string key = $"{nameof(FileHelper)}_Query_{123}";
            //    List<Program> programList = CustomCache.GetValue<List<Program>>(key, () => FileHelper.Query<Program>(123));
            //}

            //for (int i = 0; i < 5; i++)
            //{
            //    Console.WriteLine($"获取{nameof(RemoteHelper)} {i}次 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");

            //    string key = $"{nameof(RemoteHelper)}_Query_{123}";
            //    List<Program> programList = CustomCache.GetValue<List<Program>>(key, () => RemoteHelper.Query<Program>(123));
            //}
            #endregion

            #region 缓存清理
            {
                //缓存核心优化就是重用结果,下次请求用这次的结果
                //数据如果有变化还是用的上次的数据,用的就是脏数据;缓存难免有脏数据
                //需要根据业务分类缓存,尽量减少脏数据

                {
                    1 个人的权限变化,缓存应该失效
                      数据更新应该只影响单挑缓存,常规做法是Remove,而不是更新
                      因为缓存是用来提升性能的,而不是数据保存的,因此不需要更新,只需要删除就好
                      如果下次用上了,到时候再初始化
                    //string name = "XiaoWang";
                    //CustomCache.Remove(name);
                    //List<string> menu = null;
                    //if (!CustomCache.Exists(name))
                    //{
                    //    menu = new List<string>() { "123", "124", "125" };
                    //    CustomCache.Add(name, menu);
                    //}
                    //else
                    //{
                    //    menu = CustomCache.GetT<List<string>>(name);
                    //}
                }
                {
                    2 废弃某个菜单,影响一批用户的缓存

                    全部删除影响太大
                    //CustomCache.RemoveAll();

                    找出每个用户单独删除成本太大

                    那么就删除所有用户的菜单权限,别影响其他的缓存?
                    a) 添加缓存时有规则的命名key,在key上带上菜单标志,比如menu
                    b) 清理时清理key中名字有menu的,这样所有用户的菜单缓存就清理了,其他业务的缓存不受影响
                    //CustomCache.RemoveCondition(t => t.Contains("menu"));
                }
                {
                    3.第三方修改数据,缓存并不知道;但是有时候是没办法的,比如从数据库修改
                    a)提供个清理缓存的接口给第三方
                    b)给缓存加上过期时间,定期清理,减少脏数据的影响范围

                    //for (int i = 0; i < 10_000; i++)
                    //{
                    //    int k = i;
                    //    Task.Run(() => CustomCacheTiming.Add($"TestKey_{k}", $"TestKey_{k}", 10));
                    //}

                    //for (int i = 0; i < 10_000; i++)
                    //{
                    //    int k = i;
                    //    Task.Run(() => CustomCacheTiming.Remove($"TestKey_{k}"));
                    //}

                    //for (int i = 0; i < 10_000; i++)
                    //{
                    //    int k = i;
                    //    Task.Run(() => CustomCacheTiming.Exists($"TestKey_{k}"));
                    //}
                }
                {
                    for (int i = 0; i < 10_000; i++)
                    {
                        int k = i;
                        Task.Run(() => CustomCacheTimingSectioning.Add($"TestKey_{k}", $"TestKey_{k}", 10));
                    }

                    for (int i = 0; i < 10_000; i++)
                    {
                        int k = i;
                        Task.Run(() => CustomCacheTimingSectioning.Remove($"TestKey_{k}"));
                    }

                    for (int i = 0; i < 10_000; i++)
                    {
                        int k = i;
                        Task.Run(() => CustomCacheTimingSectioning.Exists($"TestKey_{k}"));
                    }
                }
            }
            #endregion
        }


    }
}
using System;
using System.Collections.Generic;

namespace Common
{
    /// <summary>
    /// 第三方数据存储和获取
    /// </summary>
    public class CustomCache
    {
        /// <summary>
        /// private:避免被外部调用,数据容器私有,保证安全
        /// static:不被GC
        /// 字典:读写效率高
        /// </summary>
        private static Dictionary<string, object> Dic = new Dictionary<string, object>();

        public static void Add(string key, object oValue)
        {
            Dic.Add(key, oValue);
        }

        public static bool Exists(string key)
        {
            return Dic.ContainsKey(key);
        }

        public static T GetT<T>(string key)
        {
            if (!Dic.ContainsKey(key))
                throw new Exception($"没有查找的值{key}");
            return (T)Dic[key];
        }

        public static void Remove(string key)
        {
            Dic.Remove(key);
        }

        public static void RemoveAll()
        {
            Dic.Clear();
        }

        public static void RemoveCondition(Func<string,bool> func)
        {
            List<string> keyList = new List<string>();
            foreach (var item in Dic)
            {
                if (func.Invoke(item.Key))
                    keyList.Add(item.Key);
            }
            keyList.ForEach(t => Dic.Remove(t));
        }

        public static T GetValue<T>(string key, Func<T> func)
        {
            T programList = default(T);
            if (!Exists(key))
            {
                programList = (T)func.Invoke();
                Add(key, programList);
            }
            else
            {
                programList = GetT<T>(key);
            }
            return programList;
        }
    }
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 第三方数据存储和获取
    /// 
    /// 过期策略:
    /// 永久有效
    /// 绝对过期--设置个时间点,超过就过期
    /// 滑动过期--多久之后过期,如果期间再次查询/更新/检查存在,有效期再次延长
    /// 
    /// 主动清理+被动清理,保证过期数据不会被查询;过期数据也不会滞留太久
    /// 多线程操作非线程安全的容器,会冲突
    /// 1.线程安全容器    ConcurrentDictionary  需要引用using System.Collections.Concurrent;
    /// 2.lock  Add/Remove/遍历       
    /// 
    /// 锁能解决问题,但是性能怎么办?
    /// 分片,多个容器,多个锁,容器之间可以并发
    /// </summary>
    public class CustomCacheTiming
    {
        private static readonly object Lock = new object();
        //主动清理
        static CustomCacheTiming()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    try
                    {
                        //Thread.Sleep(1000 * 60 * 10);
                        List<string> keyList = new List<string>();
                        lock (Lock)
                        {
                            foreach (var item in Dic)
                            {
                                if (item.Value.ObsoleteType != ObsoleteType.Never && item.Value.DeadLine < DateTime.Now)//过期清理
                                {
                                    keyList.Add(item.Key);
                                }
                            }
                        }
                        keyList.ForEach(s => Remove(s));

                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("异常");
                        continue;
                    }
                }
            });
        }

        /// <summary>
        /// private:避免被外部调用,数据容器私有,保证安全
        /// static:不被GC
        /// 字典:读写效率高
        /// </summary>
        private static Dictionary<string, CacheModel> Dic = new Dictionary<string, CacheModel>();

        /// <summary>
        /// 永不过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oValue"></param>
        public static void Add(string key, object oValue)
        {
            CacheModel cacheModel = new CacheModel()
            {
                Value = oValue,
                ObsoleteType = ObsoleteType.Never
            };
            lock (Lock)
            {
                Dic.Add(key, cacheModel);
            }
        }

        /// <summary>
        /// 绝对过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oValue"></param>
        public static void Add(string key, object oValue, int outTimeSecond)
        {
            CacheModel cacheModel = new CacheModel()
            {
                Value = oValue,
                ObsoleteType = ObsoleteType.Absolutely,
                DeadLine = DateTime.Now.AddSeconds(outTimeSecond)
            };
            lock (Lock)
            {
                Dic.Add(key, cacheModel);
            }
        }

        /// <summary>
        /// 滑动过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oValue"></param>
        public static void Add(string key, object oValue, TimeSpan duration)
        {
            CacheModel cacheModel = new CacheModel()
            {
                Value = oValue,
                ObsoleteType = ObsoleteType.Absolutely,
                DeadLine = DateTime.Now.Add(duration),
                Duration = duration
            };
            lock (Lock)
            {
                Dic.Add(key, cacheModel);
            }
        }

        /// <summary>
        /// Get前必须执行此方法
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool Exists(string key)
        {
            if (Dic.ContainsKey(key))
            {
                CacheModel cacheModel = Dic[key];
                switch (cacheModel.ObsoleteType)
                {
                    case ObsoleteType.Never:
                        return true;
                    case ObsoleteType.Absolutely:
                        if (cacheModel.DeadLine < DateTime.Now)
                        {

                            Dic.Remove(key);
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    case ObsoleteType.Relative:
                        if (cacheModel.DeadLine < DateTime.Now)
                        {

                            Dic.Remove(key);
                            return false;
                        }
                        else
                        {
                            cacheModel.DeadLine.Add(cacheModel.Duration);
                            return true;
                        }
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public static T GetT<T>(string key)
        {
            if (!Exists(key))
                throw new Exception($"没有查找的值{key}");
            return (T)Dic[key].Value;
        }

        public static void Remove(string key)
        {
            lock (Lock)
            {
                Dic.Remove(key);
            }
        }

        public static void RemoveAll()
        {
            lock (Lock)
            {
                Dic.Clear();
            }
        }

        public static void RemoveCondition(Func<string, bool> func)
        {
            List<string> keyList = new List<string>();
            lock (Lock)
            {
                foreach (var item in Dic)
                {
                    if (func.Invoke(item.Key))
                        keyList.Add(item.Key);
                }
            }
            keyList.ForEach(t => Remove(t));
           
        }

        public static T GetValue<T>(string key, Func<T> func)
        {
            T programList = default(T);
            if (!Exists(key))
            {
                programList = (T)func.Invoke();
                Add(key, programList);
            }
            else
            {
                programList = GetT<T>(key);
            }
            return programList;
        }
    }
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 第三方数据存储和获取
    /// 
    /// 过期策略:
    /// 永久有效
    /// 绝对过期--设置个时间点,超过就过期
    /// 滑动过期--多久之后过期,如果期间再次查询/更新/检查存在,有效期再次延长
    /// 
    /// 主动清理+被动清理,保证过期数据不会被查询;过期数据也不会滞留太久
    /// 多线程操作非线程安全的容器,会冲突
    /// 1.线程安全容器    ConcurrentDictionary  需要引用using System.Collections.Concurrent;
    /// 2.lock  Add/Remove/遍历       
    /// 
    /// 锁能解决问题,但是性能怎么办?
    /// 分片,多个容器,多个锁,容器之间可以并发
    /// </summary>
    public class CustomCacheTimingSectioning
    {
        private static int CpuNumber = 0;//获取CPU数量
        private static readonly List<object> LockList = new List<object>();//多个锁
        private static List<Dictionary<string, CacheModel>> DicList = new List<Dictionary<string, CacheModel>>();//多个容器
        //主动清理
        static CustomCacheTimingSectioning()
        {
            //初始化;多个容器和对应的锁
            CpuNumber = 3;
            for (int i = 0; i < CpuNumber; i++)
            {
                DicList.Add(new Dictionary<string, CacheModel>());
                LockList.Add(new object());
            }

            Task.Run(() =>
            {
                while (true)
                {
                    for (int i = 0; i < CpuNumber; i++)
                    {
                        try
                        {
                            //Thread.Sleep(1000 * 60 * 10);
                            List<string> keyList = new List<string>();
                            lock (LockList[i])
                            {
                                foreach (var item in DicList[i])
                                {
                                    if (item.Value.ObsoleteType != ObsoleteType.Never && item.Value.DeadLine < DateTime.Now)//过期清理
                                    {
                                        keyList.Add(item.Key);
                                    }
                                }
                            }
                            keyList.ForEach(s => Remove(s));

                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("异常");
                            continue;
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 永不过期
        /// 添加时得按照算法 计算相应key进入哪个容器,用哪个锁
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oValue"></param>
        public static void Add(string key, object oValue)
        {
            CacheModel cacheModel = new CacheModel()
            {
                Value = oValue,
                ObsoleteType = ObsoleteType.Never
            };
            int dicIndex = GetDicIndex(key);
            lock (LockList[dicIndex])
            {
                DicList[dicIndex].Add(key, cacheModel);
            }
        }

        /// <summary>
        /// 绝对过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oValue"></param>
        public static void Add(string key, object oValue, int outTimeSecond)
        {
            CacheModel cacheModel = new CacheModel()
            {
                Value = oValue,
                ObsoleteType = ObsoleteType.Absolutely,
                DeadLine = DateTime.Now.AddSeconds(outTimeSecond)
            };
            int dicIndex = GetDicIndex(key);
            lock (LockList[dicIndex])
            {
                DicList[dicIndex].Add(key, cacheModel);
            }
        }

        /// <summary>
        /// 滑动过期
        /// </summary>
        /// <param name="key"></param>
        /// <param name="oValue"></param>
        public static void Add(string key, object oValue, TimeSpan duration)
        {
            CacheModel cacheModel = new CacheModel()
            {
                Value = oValue,
                ObsoleteType = ObsoleteType.Absolutely,
                DeadLine = DateTime.Now.Add(duration),
                Duration = duration
            };
            int dicIndex = GetDicIndex(key);
            lock (LockList[dicIndex])
            {
                DicList[dicIndex].Add(key, cacheModel);
            }
        }

        /// <summary>
        /// Get前必须执行此方法
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool Exists(string key)
        {
            int dicIndex = GetDicIndex(key);
            if (DicList[dicIndex].ContainsKey(key))
            {
                CacheModel cacheModel = DicList[dicIndex][key];
                switch (cacheModel.ObsoleteType)
                {
                    case ObsoleteType.Never:
                        return true;
                    case ObsoleteType.Absolutely:
                        if (cacheModel.DeadLine < DateTime.Now)
                        {

                            DicList[dicIndex].Remove(key);
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    case ObsoleteType.Relative:
                        if (cacheModel.DeadLine < DateTime.Now)
                        {

                            DicList[dicIndex].Remove(key);
                            return false;
                        }
                        else
                        {
                            cacheModel.DeadLine.Add(cacheModel.Duration);
                            return true;
                        }
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public static T GetT<T>(string key)
        {
            int dicIndex = GetDicIndex(key);
            if (!Exists(key))
                throw new Exception($"没有查找的值{key}");
            return (T)DicList[dicIndex][key].Value;
        }

        public static void Remove(string key)
        {
            int dicIndex = GetDicIndex(key);
            lock (LockList[dicIndex])
            {
                DicList[dicIndex].Remove(key);
            }
        }

        public static void RemoveAll()
        {
            for (int i = 0; i < CpuNumber; i++)
            {
                lock (LockList[i])
                {
                    DicList[i].Clear();
                }
            }
        }

        public static void RemoveCondition(Func<string, bool> func)
        {
            List<string> keyList = new List<string>();
            for (int i = 0; i < CpuNumber; i++)
            {
                lock (LockList[i])
                {
                    foreach (var item in DicList[i])
                    {
                        if (func.Invoke(item.Key))
                            keyList.Add(item.Key);
                    }
                }
            }
            keyList.ForEach(t => Remove(t));

        }

        public static T GetValue<T>(string key, Func<T> func)
        {
            T programList = default(T);
            if (!Exists(key))
            {
                programList = (T)func.Invoke();
                Add(key, programList);
            }
            else
            {
                programList = GetT<T>(key);
            }
            return programList;
        }

        private static int GetDicIndex(string key)
        {
            int hashcode = key.GetHashCode() % 10;
            if (hashcode < 4)
                return 0;
            else if (hashcode < 8)
                return 1;
            else
                return 2;
        }

    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace Common
{
    public class CacheModel
    {
        public object Value { set; get; }
        public ObsoleteType ObsoleteType { set; get; }
        public DateTime DeadLine { set; get; }
        public TimeSpan Duration { set; get; }
    }

    public enum ObsoleteType
    {
        Never,
        Absolutely,
        Relative
    }
}
using System;
using System.Collections.Generic;

namespace MyBll
{
    public class DbHelper
    {
        public static List<T> Query<T>(int index)
        {
            Console.WriteLine($"This is {typeof(DbHelper)} Query");
            long lResult = 0;
            for (int i = index; i < 100_000_000; i++)
            {
                lResult += i;
            }

            List<T> rstList = new List<T>();
            for (int i = 0; i < index % 3; i++)
            {
                rstList.Add(default(T));
            }
            return rstList;
        }
    }
}
using System;
using System.Collections.Generic;

namespace MyBll
{
    public class FileHelper
    {
        public static List<T> Query<T>(int index)
        {
            Console.WriteLine($"This is {typeof(FileHelper)} Query");
            long lResult = 0;
            for (int i = index; i < 100_000_000; i++)
            {
                lResult += i;
            }

            List<T> rstList = new List<T>();
            for (int i = 0; i < index % 3; i++)
            {
                rstList.Add(default(T));
            }
            return rstList;
        }
    }
}
using System;
using System.Collections.Generic;

namespace MyBll
{
    /// <summary>
    /// 模拟远程调用接口
    /// </summary>
    public class RemoteHelper
    {
        public static List<T> Query<T>(int index)
        {
            Console.WriteLine($"This is {typeof(RemoteHelper)} Query");
            long lResult = 0;
            for (int i = index; i < 100_000_000; i++)
            {
                lResult += i;
            }

            List<T> rstList = new List<T>();
            for (int i = 0; i < index % 3; i++)
            {
                rstList.Add(default(T));
            }
            return rstList;
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值