-NetCore 緩存之 MemoryCahe
- 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 仍然存在。
程序運行結果如下:
1.2 常用配置
下邊的例子介紹 netcore 中緩存的常用配置,直接看代碼
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddMemoryCache(options =>
{
//緩存大小
options.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
//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}】");
});
_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 清除緩存的回調只能是一個)。
程序執行結果
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, value, reason, 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", "myvalue", cacheEntityOps);
Console.WriteLine(memoryCache.Get("mykey") ?? "緩存被清除了");
//通過代碼清除緩存
tokenSource.Cancel();
Console.WriteLine(memoryCache.Get("mykey") ?? "緩存被清除了");
}
}
tokenSource.Cancel 方法發送取消信號,這個方法會觸發緩存過期,基於此我們可以通過 Cancel 方法靈活的實現自定義的緩存策略。
程序執行結果如下:
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;
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/QT72Hq0PrPKEvFV9REGMGw