1 Net Framewoke的緩存
1.1 System.Web.Caching
System.Web.Caching應該是咱們最熟悉的緩存類庫了,作ASP.NET開發時用到緩存基本都是使用的這個緩存組件,簡單回顧一下用法吧
using System.Web;
using System.Web.Caching;
namespace FrameCache
{
class Program
{
static void Main(string[] args)
{
//1.簡單緩存,value能夠是任何類型
HttpRuntime.Cache.Insert("mykey", "myvalue");
Console.WriteLine($"Key爲mykey的緩存:{HttpRuntime.Cache["mykey"]}");
//2.使用緩存依賴項
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節點:{resultDs.Tables["food"].Rows[0]["f1"]}");
Console.ReadKey();
}
}
}
簡單的緩存就不說了,添加一下key和value就能夠,緩存依賴項CacheDependency是更新緩存的重要手段,但緩存依賴項發生變化時緩存就會被清理。上邊栗子中緩存只依賴一個文件,當緩存依賴多個文件時能夠這樣設置: CacheDependency cdp=new CacheDependency(new string []{"111.xml","222.xml"}); 。栗子中someCacheData.xml中的內容是:
<?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>
運行程序結果以下:

1.2 System.Runtime.Caching
Net Framework中的MemoryCache類就是來自於這個類庫,也是開發中常常用到的類庫,net core中的緩存用法和這個類庫十分類似。簡單看一下用法吧
using System.Runtime.Caching;
namespace FrameCache
{
class Program
{
static void Main(string[] args)
{
//緩存的配置
CacheItemPolicy policy = new CacheItemPolicy()
{
//緩存被刪除是的回調
RemovedCallback = (arguments) => { Console.WriteLine($"緩存被移除的緣由:{arguments.RemovedReason}"); },
//滑動過時時間
SlidingExpiration = TimeSpan.FromSeconds(5),
//絕對過時時間
//AbsoluteExpiration = DateTime.Now.AddSeconds(5),
//優先級有兩種: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 對象用於對緩存項作一個設置,如設置絕對/滑動過時時間,優先級,緩存被清理時的回調函數等。程序運行結果以下,若是咱們把線程休眠的代碼註釋掉,則輸出爲 「myvlaue」。

2 Net core的緩存介紹
netcore中的緩存用戶和 System.Runtime.Caching 很類似,可是在功能上作了加強:緩存的key能夠支持object類型(.netframework中緩存key只支持string);提供了泛型支持;能夠對緩存和單個緩存項的大小作限定,能夠設定緩存的壓縮比例(如緩存最大設置爲100M,壓縮比例爲0.2,那麼緩存達到一百兆時會清除20M的緩存數據,清除時優先級低的緩存項會被優先清除);此外微軟提供了Sqlserver和Redis的緩存支持,可讓咱們更方便地實現分佈式緩存。
2.1 MemoryCache
1.過時時間
netcore中緩存相關的類庫都在 Microsoft.Extensions.Caching ,使用MemoryCache首先安裝包
Install-Package Microsoft.Extensions.Caching.Memory
使用的方式和基本同樣,咱們簡單看一下代碼
using Microsoft.Extensions.Caching.Memory;
namespace CacheDemo
{
class Program
{
static void Main(string[] args)
{
MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions() { });
//1.最簡單使用方式
memoryCache.Set("mykey", "myvalue");
//2.絕對過時時間,3秒後過時
memoryCache.Set("key1", "value1", new DateTimeOffset(DateTime.Now.AddSeconds(3)));
//3.絕對過時時間,效果同上
memoryCache.Set("key2", "value2", TimeSpan.FromSeconds(3));
//4.滑動過時時間,3秒後,即三秒鐘內被訪問,則從新刷新緩存時間爲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都是使用的絕對過時時間,key3使用的相對過時時間,2秒後第一次訪問key一、key二、key3都沒過時,其中key3的過時時間刷新了,從新設置爲3秒後,因此再次暫停2秒後,key一、key2都過時了,key3仍然存在。程序運行結果以下:

2.經常使用配置
上邊咱們知道了netcore中緩存的簡單用法,下邊的栗子介紹netcore中緩存的經常使用配置,直接看代碼
class Program
{
static void Main(string[] args)
{
//緩存的配置
MemoryCacheOptions cacheOps = new MemoryCacheOptions()
{
//緩存最大爲100份
//##注意netcore中的緩存是沒有單位的,緩存項和緩存的相對關係
SizeLimit = 100,
//緩存滿了時,壓縮20%(即刪除20份優先級低的緩存項)
CompactionPercentage = 0.2,
//兩秒鐘查找一次過時項
ExpirationScanFrequency = TimeSpan.FromSeconds(3)
};
MemoryCache myCache = new MemoryCache(cacheOps);
//單個緩存項的配置
MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions()
{
//絕對過時時間1
//AbsoluteExpiration = 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}】");
});
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中設置緩存和緩存項大小是沒有單位的,緩存被清空的回調函數能夠註冊多個(System.Runtime.Caching清除緩存的回調只能是一個)。程序執行結果

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實現緩存過時策略的兩個例子:
① 監控文件
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的實現類,經過輪詢監控文件變化
cacheEntityOps.AddExpirationToken(new Microsoft.Extensions.FileProviders.Physical.PollingFileChangeToken(fileInfo));
//緩存失效時,回調函數
cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"文件【{key}】改動了"); });
//添加緩存,key爲文件名,value爲文件內容
myCache.Set(fileInfo.Name, File.ReadAllText(fileName), cacheEntityOps);
Console.WriteLine(myCache.Get(fileInfo.Name));
}
}
PollingFileChangeToken經過輪詢來監控文件有沒有發生變化,若是文件中的內容發生改變,緩存就會自動過時。
② 經過代碼控制緩存過時
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", "myvalue", cacheEntityOps);
Console.WriteLine(memoryCache.Get("mykey") ?? "緩存被清除了");
//經過代碼清除緩存
tokenSource.Cancel();
Console.WriteLine(memoryCache.Get("mykey") ?? "緩存被清除了");
}
}
tokenSource.Cancel方法發送取消信號,這個方法會觸發緩存過時,基於此咱們能夠經過Cancel方法靈活的實現自定義的緩存策略。程序執行結果以下:

2.2 RedisCache
微軟給netcore的緩存提供了Redis和Sqlserver的實現,經過Sqlserver來緩存的場景比較少,這裏咱們簡單看一下官方提供的Redis緩存用法。
準備工做:我已經在一臺Linu虛擬機上部署了Redis服務,虛擬機IP爲192.168.70.99,Redis採用默認端口6379,密碼是xxxxx。我開發使用的電腦能夠鏈接到虛擬機上的Redis服務器。
首先添加包
Install-Package Microsoft.Extensions.Caching
Install-Package Microsoft.Extensions.Caching.Redis
而後咱們寫一個簡單的控制檯程序實現一下netcore中的redis緩存實現,代碼以下:
static void Main(string[] args)
{
//獲取RedisCache實例
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"));
}
執行完成,緩存數據以Hash表形式存儲在redis中,以下:

這裏只是介紹了netcore中redis緩存的簡單用法,其實官方提供的Redis緩存擴展中的Api不多,遠沒有MemoryCache那麼多,咱們使用netcore中的Redis緩存時,更多要使用Redis自身提供的功能。