C#系列之聊聊.Net Core的InMemoryCache

來源:互聯網
上載者:User

暴王
個人部落格:http://www.boydwang.com/2017/12/net-core-in-memory-cache/

這兩天在看.net core的in memory cache,這裡記錄一下用法,主要涉及MemoryCache的Get/Set/Expire/Flush。
首先我們先用dotnet命令建立一個mvc的項目,這裡我們將使用postman來請求server,

dotnet new MVC 

因為我們要用到 Microsoft.Extensions.Caching.Memory這個nuget包,所以需要添加引用,用VsCode(或任何編輯器)開啟剛才建的mvc項目路徑下的*.csproj檔案,在這裡我的是cache.csproj,找到這個標籤,添加如下代碼:

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

注意版本號碼可能不一樣,我用的是.net core 2.0.
之後我們需要註冊cache服務,開啟Startup.cs檔案,找到ConfigureServices方法,添加如下代碼:

services.AddMemoryCache();

ConfigureServices方法看起來應該是這樣:

public void ConfigureServices(IServiceCollection services){    services.AddMemoryCache();    services.AddMvc();}

之後我們就可以在controller裡通過構造注入的方式使用InMemoryCache啦。
開啟HomeController或者自己建立一個Controller,在修改構造方法

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

先來看看MemoryCache的定義:

Constructors:MemoryCache(IOptions)Properties:Count(Gets the count of the current entries for diagnostic purposes.)Methods:Compact(Double)CreateEntry(Object)Dispose()Dispose(Boolean)Finalize()Remove(Object)TryGetValue(Object, Object)Extension Methods:Get(IMemoryCache, Object)Get(IMemoryCache, Object)GetOrCreate(IMemoryCache, Object, Func)GetOrCreateAsync(IMemoryCache, Object, Func>)Set(IMemoryCache, Object, TItem)Set(IMemoryCache, Object, TItem, MemoryCacheEntryOptions)Set(IMemoryCache, Object, TItem, IChangeToken)Set(IMemoryCache, Object, TItem, DateTimeOffset)Set(IMemoryCache, Object, TItem, TimeSpan)TryGetValue(IMemoryCache, Object, TItem)

我們用到的大部分都是 擴 展 方 法,這是一個奇怪的現象,但這不是這篇文章討論的重點,這裡會使用到

TryGetValue(Object, Object)Set<TItem>(IMemoryCache, Object, TItem, MemoryCacheEntryOptions)

這兩個方法,來Get/Set/Expire快取項目。

首先我們來添加一個get的webapi:

[HttpGet("cache/{key}")]public IActionResult GetCache(string key){    object result = new object();    _cache.TryGetValue(key, out result);    return new JsonResult(result);}

它接受一個key作為參數,如果找到則返回找到的值,若找不到則返回空
現在我們可以在命令列裡輸入

dotnet restoredotnet run

來啟動web項目,之後我們可以通過

http://localhost:5000/cache/{key}

這個url來訪問cache,此時cache還沒有值

因為此時我們還沒有set值。
接下來添加一個Set方法,在添加之前,我們先來看一下MemoryCacheEntryOptions的定義。

Constructors:
MemoryCacheEntryOptions()

Properties:
AbsoluteExpiration
AbsoluteExpirationRelativeToNow
ExpirationTokens
PostEvictionCallbacks
Priority
Size
SlidingExpiration

Extension Methods:
AddExpirationToken(MemoryCacheEntryOptions, IChangeToken)
RegisterPostEvictionCallback(MemoryCacheEntryOptions, PostEvictionDelegate)
RegisterPostEvictionCallback(MemoryCacheEntryOptions, PostEvictionDelegate, Object)
SetAbsoluteExpiration(MemoryCacheEntryOptions, DateTimeOffset)
SetAbsoluteExpiration(MemoryCacheEntryOptions, TimeSpan)
SetPriority(MemoryCacheEntryOptions, CacheItemPriority)
SetSize(MemoryCacheEntryOptions, Int64)
SetSlidingExpiration(MemoryCacheEntryOptions, TimeSpan)

這裡有幾個概念:
AbsoluteExpiration
代表了絕對絕對逾時時間,在一定時間後必定逾時(比如15分鐘)

SlidingExpiration
代表了滑動逾時時間(我自己翻譯的。。),滑動的意思就是假如你設定了SlidingExpiration逾時時間為5分鐘,如果在5分鐘裡,有新的請求來擷取這個cached item,那麼這個5分鐘會重設,直到超過5分鐘沒有請求來,才逾時

CacheItemPriority
這是一個枚舉,代表了緩衝的優先順序,預設值為Normal,如果設定為NeverRemove則一直不逾時。

High    Low NeverRemove Normal

RegisterPostEvictionCallback
這是個方法需要傳一個回調,在快取項目被移除(逾時)的時候觸發回調。

接著我們來添加一個Set方法,並且為它添加一個canceltoken,以便我們能夠手動控制強制清空緩衝。

private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();[HttpPost("cache/")]public IActionResult SetCache([FromBody]CacheItem item){    var cacheEntryOptions = new MemoryCacheEntryOptions()    .SetAbsoluteExpiration(TimeSpan.FromMinutes(5))    .RegisterPostEvictionCallback(DependentEvictionCallback, null)    .AddExpirationToken(new CancellationChangeToken(cancellationTokenSource.Token));    _cache.Set(item.key, item.value, cacheEntryOptions);    return Ok();}

然後我們就可以用postman的post請求來Set緩衝了,地址是:

http://localhost:5000/cache

接下來我們來添加一個flush api,我們能夠手動清空緩衝。這裡我們利用了上面在Set時添加的cancellationTokenSource

[HttpGet("cache/flush")]public IActionResult Flush(){    cancellationTokenSource.Cancel();    return Ok();}

訪問地址:

http://localhost:5000/cache/flush

調用這個api會發現在console裡有一行輸出

Parent entry was evicted. Reason: TokenExpired, Key: a.

可以在多個快取項目中添加同一個token,達到同時清除多個快取項目的目的。

遇到的坑:
1.token不work的問題.
我在最初實現的時候,加了一個token,是這麼寫的

private CancellationTokenSource cancellationTokenSource;public HomeController(IMemoryCache cache){    this._cache = cache;    cancellationTokenSource = new CancellationTokenSource();}[HttpGet("cache/flush")]public IActionResult Flush(){    cancellationTokenSource.Cancel();    return Ok();}

然後發現調用flush一直不生效,cache並沒有被清掉,很納悶,以為我的token方法用的有問題。
直到我換成了下面的代碼,大家體會一下。

private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();public HomeController(IMemoryCache cache){    this._cache = cache;}[HttpGet("cache/flush")]public IActionResult Flush(){    cancellationTokenSource.Cancel();    return Ok();}

僅僅是一個static的問題,就產生了不一樣的結果,這是因為每次httprequest過來,都會啟動一個新線程去響應它,因此在set的時候加進去的那個token,並不是flush請求過來的token,因為又調用了一次構造方法,產生了一個新的CancellationTokenSource對象,因此調用token.Cancel()方法必然會失效,因此改成了static,讓每次請求的都是同一個token,這樣就不會造成不同token導致的Cancel方法不work的問題,清空cache也就能正常工作了。

2.RegisterPostEvictionCallback重複觸發的問題

RegisterPostEvictionCallback不僅僅在緩衝逾時的時候觸發,也會在緩衝被替換(更新)的時候觸發,在PostEvictionDelegate有一個參數為EvictionReason指明了快取項目被移除的原因

 public delegate void PostEvictionDelegate(object key, object value, EvictionReason reason, object state);
EvictionReasonNone = 0,Removed = 1,  快取項目被Remove()方法移除Replaced = 2,  快取項目被更新Expired = 3,  快取項目逾時TokenExpired = 4, 緩衝由token觸發逾時Capacity = 5 緩衝空間不足

因此我們需要在callback雷根據需要判斷緩衝是因為什麼原因被移除,才能避免意外的回調觸發。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.