一文掌握.Net?core中的緩存
Cache(緩存)是優(yōu)化web應(yīng)用的常用方法,緩存存放在服務(wù)端的內(nèi)存中,被所有用戶共享。由于Cache存放在服務(wù)器的內(nèi)存中,所以用戶獲取緩存資源的速度遠(yuǎn)比從服務(wù)器硬盤中獲取快,但是從資源占有的角度考慮緩存也不是越多越好。經(jīng)常要用到且不會(huì)頻繁改變且被用戶共享的數(shù)據(jù)很適合放在緩存中。在介紹netcore的緩存前我們先回顧下net framework中的緩存技術(shù)。
net framework中常用的緩存有兩種:System.Runtime.Caching和System.Web.Caching
1 Net Framewoke的緩存
1.1 System.Web.Caching
System.Web.Caching應(yīng)該是我們最熟悉的緩存類庫(kù)了,做ASP.NET開發(fā)時(shí)用到緩存基本都是使用的這個(gè)緩存組件,簡(jiǎn)單回顧一下用法吧
using System.Web; using System.Web.Caching; namespace FrameCache { class Program { static void Main(string[] args) { //1.簡(jiǎn)單緩存,value可以是任何類型 HttpRuntime.Cache.Insert("mykey", "myvalue"); Console.WriteLine($"Key為mykey的緩存:{HttpRuntime.Cache["mykey"]}"); //2.使用緩存依賴項(xiàng) string path = Path.Combine(Environment.CurrentDirectory, @"someCacheData.xml"); DataSet ds = new DataSet(); ds.ReadXml(path); if (HttpRuntime.Cache.Get("myxml") == null) { //Dataset添加到緩存 System.Web.HttpRuntime.Cache.Insert("myxml", ds, new CacheDependency(path)); } //從緩存中獲取Dataset DataSet resultDs = (DataSet)HttpRuntime.Cache.Get("myxml"); Console.WriteLine($"food下的f1節(jié)點(diǎn):{resultDs.Tables["food"].Rows[0]["f1"]}"); Console.ReadKey(); } } }
簡(jiǎn)單的緩存就不說(shuō)了,添加一下key和value就可以,緩存依賴項(xiàng)CacheDependency是更新緩存的重要手段,但緩存依賴項(xiàng)發(fā)生變化時(shí)緩存就會(huì)被清理。上邊栗子中緩存只依賴一個(gè)文件,當(dāng)緩存依賴多個(gè)文件時(shí)可以這樣設(shè)置: CacheDependency cdp=new CacheDependency(new string []{"111.xml","222.xml"});。栗子中someCacheData.xml中的內(nèi)容是:
<?xml version="1.0" encoding="utf-8" ?> <MyCache> <animals> <a1>cat</a1> <a2>dog</a2> </animals> <food> <f1>apple</f1> <f2>pear</f2> </food> </MyCache>
運(yùn)行程序結(jié)果如下:
1.2 System.Runtime.Caching
Net Framework中的MemoryCache類就是來(lái)自于這個(gè)類庫(kù),也是開發(fā)中經(jīng)常用到的類庫(kù),net core中的緩存用法和這個(gè)類庫(kù)十分相似。簡(jiǎn)單看一下用法吧
using System.Runtime.Caching; namespace FrameCache { class Program { static void Main(string[] args) { //緩存的配置 CacheItemPolicy policy = new CacheItemPolicy() { //緩存被刪除是的回調(diào) RemovedCallback = (arguments) => { Console.WriteLine($"緩存被移除的原因:{arguments.RemovedReason}"); }, //滑動(dòng)過(guò)期時(shí)間 SlidingExpiration = TimeSpan.FromSeconds(5), //絕對(duì)過(guò)期時(shí)間 //AbsoluteExpiration = DateTime.Now.AddSeconds(5), //優(yōu)先級(jí)有兩種:Default,NotRemovable(不可移除) Priority = System.Runtime.Caching.CacheItemPriority.NotRemovable }; //添加緩存,key為mykey,值是myvalue , System.Runtime.Caching.MemoryCache.Default.Add("mykey", "myvalue", policy); Thread.Sleep(6000); Console.WriteLine(MemoryCache.Default.Get("mykey")); Console.ReadKey(); } } }
CacheItemPolicy 對(duì)象用于對(duì)緩存項(xiàng)做一個(gè)設(shè)置,如設(shè)置絕對(duì)/滑動(dòng)過(guò)期時(shí)間,優(yōu)先級(jí),緩存被清理時(shí)的回調(diào)函數(shù)等。程序運(yùn)行結(jié)果如下,如果我們把線程休眠的代碼注釋掉,則輸出為 “myvlaue”。
2 Net core的緩存介紹
netcore中的緩存用戶和System.Runtime.Caching很相似,但是在功能上做了增強(qiáng):緩存的key可以支持object類型(.netframework中緩存key只支持string);提供了泛型支持;可以對(duì)緩存和單個(gè)緩存項(xiàng)的大小做限定,可以設(shè)定緩存的壓縮比例(如緩存最大設(shè)置為100M,壓縮比例為0.2,那么緩存達(dá)到一百兆時(shí)會(huì)清除20M的緩存數(shù)據(jù),清除時(shí)優(yōu)先級(jí)低的緩存項(xiàng)會(huì)被優(yōu)先清除);此外微軟提供了Sqlserver和Redis的緩存支持,可以讓我們更方便地實(shí)現(xiàn)分布式緩存。
2.1 MemoryCache
1.過(guò)期時(shí)間
netcore中緩存相關(guān)的類庫(kù)都在Microsoft.Extensions.Caching,使用MemoryCache首先安裝包
Install-Package Microsoft.Extensions.Caching.Memory
使用的方式和基本一樣,我們簡(jiǎn)單看一下代碼
using Microsoft.Extensions.Caching.Memory; namespace CacheDemo { class Program { static void Main(string[] args) { MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions() { }); //1.最簡(jiǎn)單使用方式 memoryCache.Set("mykey", "myvalue"); //2.絕對(duì)過(guò)期時(shí)間,3秒后過(guò)期 memoryCache.Set("key1", "value1", new DateTimeOffset(DateTime.Now.AddSeconds(3))); //3.絕對(duì)過(guò)期時(shí)間,效果同上 memoryCache.Set("key2", "value2", TimeSpan.FromSeconds(3)); //4.滑動(dòng)過(guò)期時(shí)間,3秒后,即三秒鐘內(nèi)被訪問,則重新刷新緩存時(shí)間為3秒后 memoryCache.Set("key3", "value3", new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromSeconds(3), }); Console.WriteLine("-----------暫停2秒"); Thread.Sleep(2000);//暫停2秒 Console.WriteLine($"key1的值:{memoryCache.Get("key1") ?? "key1被清除"}"); Console.WriteLine($"key2的值:{memoryCache.Get("key2") ?? "key2被清除"}"); Console.WriteLine($"key3的值:{memoryCache.Get("key3") ?? "key3被清除"}"); Console.WriteLine("-----------暫停2秒"); Thread.Sleep(2000);//再次暫停2秒 Console.WriteLine($"key1的值:{memoryCache.Get("key1") ?? "key1被清除"}"); Console.WriteLine($"key2的值:{memoryCache.Get("key2") ?? "key2被清除"}"); Console.WriteLine($"key3的值:{memoryCache.Get("key3") ?? "key3被清除"}"); } } }
在栗子中key1,key2都是使用的絕對(duì)過(guò)期時(shí)間,key3使用的相對(duì)過(guò)期時(shí)間,2秒后第一次訪問key1、key2、key3都沒過(guò)期,其中key3的過(guò)期時(shí)間刷新了,重新設(shè)置為3秒后,所以再次暫停2秒后,key1、key2都過(guò)期了,key3仍然存在。程序運(yùn)行結(jié)果如下:
2.常用配置
上邊我們知道了netcore中緩存的簡(jiǎn)單用法,下邊的栗子介紹netcore中緩存的常用配置,直接看代碼
class Program { static void Main(string[] args) { //緩存的配置 MemoryCacheOptions cacheOps = new MemoryCacheOptions() { //緩存最大為100份 //##注意netcore中的緩存是沒有單位的,緩存項(xiàng)和緩存的相對(duì)關(guān)系 SizeLimit = 100, //緩存滿了時(shí),壓縮20%(即刪除20份優(yōu)先級(jí)低的緩存項(xiàng)) CompactionPercentage = 0.2, //兩秒鐘查找一次過(guò)期項(xiàng) ExpirationScanFrequency = TimeSpan.FromSeconds(3) }; MemoryCache myCache = new MemoryCache(cacheOps); //單個(gè)緩存項(xiàng)的配置 MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions() { //絕對(duì)過(guò)期時(shí)間1 //AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(2)), //絕對(duì)過(guò)期時(shí)間2 //AbsoluteExpirationRelativeToNow=TimeSpan.FromSeconds(3), //相對(duì)過(guò)期時(shí)間 SlidingExpiration = TimeSpan.FromSeconds(3), //優(yōu)先級(jí),當(dāng)緩存壓縮時(shí)會(huì)優(yōu)先清除優(yōu)先級(jí)低的緩存項(xiàng) Priority = CacheItemPriority.Low,//Low,Normal,High,NeverRemove //緩存大小占1份 Size = 1 }; //注冊(cè)緩存項(xiàng)被清除時(shí)的回調(diào),可以注冊(cè)多個(gè)回調(diào) cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"回調(diào)函數(shù)輸出【鍵:{key},值:{value},被清除的原因:{reason}】"); }); myCache.Set("mykey", "myvalue", cacheEntityOps); Console.WriteLine($"mykey的值:{myCache.Get("mykey") ?? "mykey緩存被清除了"}"); Console.WriteLine("------------------暫停3秒"); Thread.Sleep(3000); Console.WriteLine($"mykey的值:{myCache.Get("mykey") ?? "mykey緩存被清除了"}"); Console.ReadKey(); } } }
這里需要注意netcore中設(shè)置緩存和緩存項(xiàng)大小是沒有單位的,緩存被清空的回調(diào)函數(shù)可以注冊(cè)多個(gè)(System.Runtime.Caching清除緩存的回調(diào)只能是一個(gè))。程序執(zhí)行結(jié)果
3.IChangeToken
上邊我們已經(jīng)簡(jiǎn)單了解了通過(guò)滑動(dòng)過(guò)期時(shí)間和絕對(duì)過(guò)期時(shí)間來(lái)控制緩存的有效性,但是有時(shí)緩存的過(guò)期與否和時(shí)候沒有聯(lián)系,如我們緩存一個(gè)文件的內(nèi)容,不管緩存多久只要文件沒有發(fā)生變化緩存都是有效的。在net framework中我們可以通過(guò)CacheDependency來(lái)控制,在net core中怎么控制呢?net core中我們可以使用IChangeToken接口輕松實(shí)現(xiàn)緩存的過(guò)期策略。先看一下IChangeToken接口:
public interface IChangeToken { // 是否有變化發(fā)生 bool HasChanged { get; } // token是否會(huì)調(diào)用回調(diào)函數(shù),為true時(shí)才會(huì)有效 bool ActiveChangeCallbacks { get; } // 注冊(cè)一個(gè)回調(diào)函數(shù),當(dāng)有變化時(shí)觸發(fā)回調(diào) IDisposable RegisterChangeCallback(Action<object> callback, object state); }
看一下IChangeToken實(shí)現(xiàn)緩存過(guò)期策略的兩個(gè)例子:
① 監(jiān)控文件
class Program { static void Main(string[] args) { string fileName = Path.Combine(Environment.CurrentDirectory, "someCacheData.xml"); FileInfo fileInfo = new FileInfo(fileName); MemoryCache myCache = new MemoryCache(new MemoryCacheOptions() { }); MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions(); //PollingFileChangeToken是IChangeToken的實(shí)現(xiàn)類,通過(guò)輪詢監(jiān)控文件變化 cacheEntityOps.AddExpirationToken(new Microsoft.Extensions.FileProviders.Physical.PollingFileChangeToken(fileInfo)); //緩存失效時(shí),回調(diào)函數(shù) cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"文件【{key}】改動(dòng)了"); }); //添加緩存,key為文件名,value為文件內(nèi)容 myCache.Set(fileInfo.Name, File.ReadAllText(fileName), cacheEntityOps); Console.WriteLine(myCache.Get(fileInfo.Name)); } }
PollingFileChangeToken通過(guò)輪詢來(lái)監(jiān)控文件有沒有發(fā)生變化,如果文件中的內(nèi)容發(fā)生改變,緩存就會(huì)自動(dòng)過(guò)期。
② 通過(guò)代碼控制緩存過(guò)期
class Program { static void Main(string[] args) { MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()); MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions(); //使用CancellationChangeToken控制緩存過(guò)期 CancellationTokenSource tokenSource = new CancellationTokenSource(); cacheEntityOps.AddExpirationToken(new CancellationChangeToken(tokenSource.Token)); //設(shè)置緩存 memoryCache.Set("mykey", "myvalue", cacheEntityOps); Console.WriteLine(memoryCache.Get("mykey") ?? "緩存被清除了"); //通過(guò)代碼清除緩存 tokenSource.Cancel(); Console.WriteLine(memoryCache.Get("mykey") ?? "緩存被清除了"); } }
tokenSource.Cancel方法發(fā)送取消信號(hào),這個(gè)方法會(huì)觸發(fā)緩存過(guò)期,基于此我們可以通過(guò)Cancel方法靈活的實(shí)現(xiàn)自定義的緩存策略。程序執(zhí)行結(jié)果如下:
2.2 RedisCache
微軟給netcore的緩存提供了Redis和Sqlserver的實(shí)現(xiàn),通過(guò)Sqlserver來(lái)緩存的場(chǎng)景比較少,這里我們簡(jiǎn)單看一下官方提供的Redis緩存用法。
準(zhǔn)備工作:我已經(jīng)在一臺(tái)Linu虛擬機(jī)上部署了Redis服務(wù),虛擬機(jī)IP為192.168.70.99,Redis采用默認(rèn)端口6379,密碼是xxxxx。我開發(fā)使用的電腦可以連接到虛擬機(jī)上的Redis服務(wù)器。
首先添加包
Install-Package Microsoft.Extensions.Caching Install-Package Microsoft.Extensions.Caching.Redis
然后我們寫一個(gè)簡(jiǎn)單的控制臺(tái)程序?qū)崿F(xiàn)一下netcore中的redis緩存實(shí)現(xiàn),代碼如下:
static void Main(string[] args) { //獲取RedisCache實(shí)例 RedisCache redisCache = new RedisCache(new RedisCacheOptions() { Configuration = "192.168.70.99:6379,password=xxxxx", InstanceName = "MyData" }); //在redis中是以hash表的模式存放的 redisCache.SetString("Name", "jack"); redisCache.SetString("Age", "20"); redisCache.SetString("Address", "上海", new DistributedCacheEntryOptions() { //SlidingExpiration = TimeSpan.FromSeconds(3) AbsoluteExpiration = DateTimeOffset.Now.AddDays(1) }); //獲取緩存 //Console.WriteLine(redisCache.GetString("Name")); }
執(zhí)行完成,緩存數(shù)據(jù)以Hash表形式存儲(chǔ)在redis中,如下:
這里只是介紹了netcore中redis緩存的簡(jiǎn)單用法,其實(shí)官方提供的Redis緩存擴(kuò)展中的Api很少,遠(yuǎn)沒有MemoryCache那么多,我們使用netcore中的Redis緩存時(shí),更多要使用Redis自身提供的功能。
到此這篇關(guān)于.Net core中的緩存介紹的文章就介紹到這了,更多相關(guān).netcore緩存介紹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在.NET Core中用最原生的方式讀取Nacos的配置方法(推薦)
這篇文章主要介紹了在.NET Core中用最原生的方式讀取Nacos的配置方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04.NET?Core使用Autofac容器的DI依賴注入,IOC控制反轉(zhuǎn)及AOP切面編程
本文詳細(xì)講解了.NET?Core使用Autofac容器的DI依賴注入,IOC控制反轉(zhuǎn)及AOP切面編程,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02asp.net 無(wú)重復(fù)隨機(jī)數(shù)代碼
asp.net產(chǎn)生無(wú)重復(fù)隨機(jī)數(shù)的實(shí)現(xiàn)代碼2008-11-11Asp.Mvc 2.0用戶的編輯與刪除實(shí)例講解(5)
這篇文章主要介紹了Asp.Mvc 2.0用戶的編輯與刪除功能,需要的朋友可以參考下2015-08-08如何傳值在2個(gè)頁(yè)面之間 要求不刷新父頁(yè)面,并且不能用Querystring傳值
通過(guò)Cookie,因?yàn)樗瓤梢栽诜?wù)器端對(duì)其進(jìn)行操作,也可在客戶端對(duì)其進(jìn)行操作但是缺點(diǎn)是不安全,而且有時(shí)客戶端會(huì)由于安全問題禁用Cookie!2008-12-12