1. 程式人生 > 程式設計 >詳解.Net快取之MemoryCahe

詳解.Net快取之MemoryCahe

1. MemoryCahe

NetCore中的快取和System.Runtime.Caching很相似,但是在功能上做了增強,快取的key支援object型別;提供了泛型支援;可以讀快取和單個快取項的大小做限定,可以設定快取的壓縮比例。

通過實現微軟官方的Microsoft.Extensions.Caching裡面的IDistributedCache介面實現快取整合到ASPNETCore中

1.1 簡單入門

netcore中快取相關的類庫都在 Microsoft.Extensions.Caching ,使用MemoryCache首先安裝包

<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />

注入

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            //新增快取配置
            services.AddMemoryCache();
        }

使用

        private readonly IMemoryCache _cache;
        public HomeController(IMemoryCache cache)
        {
            _cache = cache;
        }

        [HttpGet]
        public string Set()
        {
            //寫
            _cache.Set("login","4545478244");
            return "";
        }

        [HttpGet]
        public string Get()
        {
            //讀
            var value = _cache.Get("login");
            return "";
        }

1.2 過期時間

            //1.最簡單使用方式
            _cache.Set("mykey","myvalue");
            //2.絕對過期時間,3秒後過期
            _cache.Set("key1","value1",new DateTimeOffset(DateTime.Now.AddSeconds(3)));
            //3.絕對過期時間,效果同上
            _cache.Set("key2","value2",TimeSpan.FromSeconds(3));
            //4.滑動過期時間,3秒後,即三秒鐘內被訪問,則重新重新整理快取時間為3秒後
            _cache.Set("key3","value3",new MemoryCacheEntryOptions
            {
                SlidingExpiration = TimeSpan.FromSeconds(3),});
            Console.WriteLine("-----------暫停2秒");
            Thread.Sleep(2000);//暫停2秒
            Console.WriteLine($"key1的值:{_cache.Get("key1") ?? "key1被清除"}");
            Console.WriteLine($"key2的值:{_cache.Get("key2") ?? "key2被清除"}");
            Console.WriteLine($"key3的值:{_cache.Get("key3") ?? "key3被清除"}");
            Console.WriteLine("-----------暫停2秒");
            Thread.Sleep(2000);//再次暫停2秒
            Console.WriteLine($"key1的值:{_cache.Get("key1") ?? "key1被清除"}");
            Console.WriteLine($"key2的值:{_cache.Get("key2") ?? "key2被清除"}");
  
程式設計客棧
Console.WriteLine($"key3的值:{_cache.Get("key3") ?? "key3被清除"}");

在例子中key1,key2都是使用的絕對過期時間,key3使用的相對過期時間,2秒後第一次訪問key1、key2、key3都沒過期,其中key3的過期時間重新整理了,重新設定為3秒後,所以再次暫停2秒後,key1、key2都過期了,key3仍然存在。

程式執行結果如下:

詳解.Net快取之MemoryCahe

1.2 常用配置

下邊的例子介紹netcore中快取的常用配置,直接看程式碼

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers(程式設計客棧);

            services.Addwww.cppcns.comMemoryCache(options =>
            {
                //快取大小
                optiogNdwEbns.SizeLimit = 3;//如果設定了該值,那麼每個set都必須設定size,並且超過了這個值的大小的會自動銷燬 
                //快取滿了時,壓縮20%(即刪除20份優先順序低的快取項)
                options.CompactionPercentage = 0.2;
                //兩秒鐘查詢一次過期項
                options.ExpirationScanFrequency = TimeSpan.FromSeconds(3);
            });
        }

        [HttpGet]
        public string TestSize()
        {
            //SizeLimit配置3
            _cache.Set("item1","11111",new MemoryCacheEntryOptions
            {
                //快取大小佔1份
                Size = 2
            });
            _cache.Set("item2","22222",new MemoryCacheEntryOptions
            {
                Size = 2
            });
            var item1 = _cache.Get("item1");//輸出 11111
            var item2 = _cache.Get("item2");//輸出 null

            return "";
        }

        [HttpGet]
        public string TestOptions()
        {
            //單個快取項的配置
            MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions()
            {
                //絕對過期時間1
                //Ab程式設計客棧soluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(2)),//絕對過期時間2
                //AbsoluteExpirationRelativeToNow=TimeSpan.FromSeconds(3),//相對過期時間
                SlidingExpiration = TimeSpan.FromSeconds(3),//優先順序,當快取壓縮時會優先清除優先順序低的快取項
                Priority = CacheItemPriority.Low,//優先順序等級:Low,Normal,High,NeverRemove
                //快取大小佔1份
                Size = 1
            };
            //註冊快取項被清除時的回撥,可以註冊多個回撥
            cacheEntityOps.RegisterPostEvictionCallback((key,value,reason,state) =>
            {
                Console.WriteLine($"回撥函式輸出【鍵:{key},值:{value},被清除的原因:{reason}】");
            });
            _cache.Set("mykey","myvalue",cacheEntityOps);
            Console.WriteLine($"mykey的值:{_cache.Get("mykey") ?? "mykey快取被清除了"}");
            Console.WriteLine("------------------暫停3秒");
            Thread.Sleep(3000);
            Console.WriteLine($"mykey的值:{_cache.Get("mykey") ?? "mykey快取被清除了"}");

            return "";
        }

注意netcore中設定快取和快取項大小是沒有單位的

快取被清空的回撥函式可以註冊多個(System.Runtime.Caching清除快取的回撥只能是一個)。

程式執行結果

詳解.Net快取之MemoryCahe

1.3 IChangeToken

上邊我們已經簡單瞭解了通過滑動過期時間和絕對過期時間來控制快取的有效性,但是有時快取的過期與否和時間沒有聯絡,比如我們快取一個檔案的內容,不管快取多久只要檔案沒有發生變化快取都是有效的。在net framework中我們可以通過CacheDependency來控制,在net core中怎麼控制呢?net core中我們可以使用IChangeToken介面輕鬆實現快取的過期策略。先看一下IChangeToken介面:

    public interface IChangeToken
    {
        // 是否有變化發生
        bool HasChanged { get; }
        // token是否會呼叫回撥函式,為true時才會有效 
        bool ActiveChangeCallbacks { get; }
        // 註冊一個回撥函式,當有變化時觸發回撥
        IDisposable RegisterChangeCallback(Action<object> callback,object state);
    }

看一下IChangeToken實現快取過期策略的兩個例子

1.3.1 監控檔案

需要安裝元件:Microsoft.Extensions.FileProviders.Physical

    internal class Program
    {
        private static void Main(string[] args)
        {
            string fileName = Path.Combine(Environment.CurrentDirectory,"someCacheData.xml");
            var fileInfo = new FileInfo(fileName);
            MemoryCache myCache = new MemoryCache(new MemoryCacheOptions() { });
            MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions();
            //PollingFileChangeToken是IChangeToken的實現類,通過輪詢監控檔案變化
            cacheEntityOps.AddExpirationToken(new Microsoft.Extensions.FileProviders.Physical.PollingFileChangeToken(fileInfo));
            //快取失效時,回撥函式
            cacheEntityOps.RegisterPostEvictionCallback((key,state) => { Console.WriteLine($"檔案【{key}】改動了"); });
            //新增快取,key為檔名,value為檔案內容
            myCache.Set(fileInfo.Name,File.ReadAllText(fileName),cacheEntityOps);
            Console.WriteLine(myCache.Get(fileInfo.Name));
        }
    }

PollingFileChangeToken通過輪詢來監控檔案有沒有發生變化,如果檔案中的內容發生改變,快取就會自動過期。

1.3.2 通過程式碼控制快取過期

    class Program
    {
        static void Main(string[] args)
        {
            MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions());
            MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions();
            //使用CancellationChangeToken控制快取過期
            CancellationTokenSource tokenSource = new CancellationTokenSource();
            cacheEntityOps.AddExpirationToken(new CancellationChangeToken(tokenSource.Token));
            //設定快取
            memoryCache.Set("mykey",cacheEntityOps);
            Console.WriteLine(memoryCache.Get("mykey") ?? "快取被清除了");
            //通過程式碼清除快取
            tokenSource.Cancel();
            Console.WriteLine(memoryCache.Get("mykey") ?? "快取被清除了");
        }
    }

tokenSource.Cancel方法傳送取消訊號,這個方法會觸發快取過期,基於此我們可以通過Cancel方法靈活的實現自定義的快取策略。

程式執行結果如下:

詳解.Net快取之MemoryCahe

1.4 引用Nuget包

直接引用我自己簡單封裝的一個Nuget包(簡單封裝自己用,不要嘲笑)

    <PackageReference Include="Common.Cache.MemoryCache" Version="1.1.0" />

注入到容器

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            //注入
            services.AddMemoryCacheExtension();
        }

使用

        # 在需要使用的地方進行注入
        private readonly IMemoryCachimg  _cache;
        public HomeController(IMemoryCachimg cache)
        {
            _cache = cache;
        }

以上就是詳解.Net快取之MemoryCahe的詳細內容,更多關於.Net快取之MemoryCahe的資料請關注我們其它相關文章!