jk's notes
  • .NET 中的缓存

.NET 中的缓存

官方文档

介绍两个主要的缓存, 其参考链接为:

  • Microsoft.Extensions.Caching.Memory
  • Microsoft.Extensions.Caching.Distributed

原则上, 缓存是优化技术, 为了让响应更快.

重要:

.NET 中有两个 MemoryCache 类, 一个在 Microsoft.Extensions.Caching.Memory 中, 另一个在 System.Runtime.Caching. 本文重点在前一个命名空间中.

Microsoft.Extensions.* 中的类都具有依赖注入特性. 其中 IMemoryCache, IDistributedCache 可用作服务.

内存中缓存

内存中的缓存, 即 Microsoft.Extensions.Caching.Memory 包.

  • IMemoryCache 是 ConcurrentDictionary<TKey, TValue> 的包装器, 其提供了丰富的 API.

  • 其中项为 ICacheEntity 类型, 存储任意的 object 类型的数据.

内存中的缓存用于单服务应用. 多服务应用建议使用分布式缓存.

缓存中的 API

缓存的使用可以看成一个 静态字典. 而过期时间可以分为:

  • 绝对过期时间
  • 滑动过期时间

在超出过期时间的时候缓存的数据被清除掉.

要设置超期, 创建 MemoryCacheEntryOptions 类型的实例, 然后设置相关属性. 超期时间是一个配置.

其文档参考

常用属性与方法为

属性或方法名描述
AbsoluteExpiration设置, 或读取缓存实体的绝对过期时间.
AbsoluteExpirationRelativeToNow设置, 或读取, 据当前的绝对过期时间.
ExpirationTokens获取 IChangeToken 实例, 该实例会影响过期时间.
RegisterPostEvictionCallBack()设置 evict 回调, 在数据超时, 从缓存中移除时触发.
MemoryCahceEntryOptions opts = new() {
  AbsoluteExpirationRelativeToNow = TimeSpan.FromSecond(5)
};

文档中介绍了一些类型与扩展供参考, 细节可以直接查看文档.

内存中的缓存示例(就是用法)

这里是重点

使用缓存:

  1. 先注册缓存服务. 调用 AddMemoryCache() 方法.
  2. 访问到 IMemoryCache 示例 (例如: 基于构造函数注入).
  3. 使用 Create 或 Set 方法来缓存数据. Set 的时候可以带上 MemoryCacheEntryOptions 对象配置过期时间.
  4. 可以在 MemoryCacheEntryOptions 中注册事件 RegisterPostEvictionCallBack(), 在数据超期时触发该事件处理函数.
  5. 获取缓存中的数据使用 TryGetValue().

示例:

image-20231213111141175

文档给出的示例 采用了基于命令行的程序 (这是另一个版本的 Demo):

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();

IMemoryCache cache =
    host.Services.GetRequiredService<IMemoryCache>();

完整代码可参考: 文档

辅助角色服务缓存

该文档提供了一个缓存模型的示例, 将缓存独立成一个后台服务, 这个案例可以看成一个单机版本的分模块的应用模型. 细节可以参考文档

待整理, 抽象出模型.

分布式缓存

分布式缓存将数据存储与进程外部, 适合多实例运行的情况.

注意, 建议只运行在测试环境中.

分布式缓存 API

相比较与内存缓存, 分布式缓存只存储字节数组.

注册使用 AddDistributedMemoryCache 方法.

创建值

涉及 API

  • IDistributedCache.SetAsync
  • IDistributedCache.Set

与内存缓存类似, 使用 DistributedCacheEntryOptions 来配置过期时间.

虽然提供了 同步版本 与 异步版本的 API. 但是不建议使用同步版本的.

DistributedCacheEntryOptions opts = new () {
  AbsoluteExpirationRelativeToNow = TimeSpan.FromSecond(5)
};
// ...
await cache.SetAsync(<key>, <bytes>, opts);

写入扩展方法

封装了一层字符串处理, 不用转 字节数组

  • DistributedCacheExtensions.SetString
  • DistributedCacheExtensions.SetStringAsync

读取值

读取返回字节数组, 需要自行转换为字符串.

  • IDistributedCache.Get
  • IDistributedCache.GetAsync

读取扩展方法

在字符串上封装了一层

  • DistributedCacheExtensions.GetString
  • DistributedCacheExtensions.GetStringAsync

更新值

无法更新值, 只有将其删除, 再重新创建. 但可以刷新其过期时间.

  • DistributedCache.Refresh
  • DistributedCache.RefreshAsync

删除值

  • IDistributedCache.Remove
  • IDistributedCache.RemoveAsync
Last Updated:
Contributors: jk