我对内存缓存的看法
我一直在研究一些处理大量数据的东西。在这样做的过程中,我意识到其中很大一部分永远不会改变,或者至少在一段固定的时间内不会改变。
所以我认为创建个人缓存存储库会很有用,当然这不是什么新鲜事,几周前我在 StackOverflow 的 post 中读到了由 Nick Craver 撰写的关于他们如何管理应用程序缓存的内容。
另外,我一直想使用缓存,它是如何工作的,逻辑以及如何让它工作,所以…为什么不!
流量
下面是一个快速流程,展示了当用户请求一个值时,拥有缓存控制权的类将如何表现。
实施
在我们开始之前
我知道,我知道。 System.Runtime.Caching 处理内存缓存。但我决定自己构建它,如果您想使用该类,请查看此处以获取操作方法。
缓存项
第一步是拥有一个存储对象值和到期日期的类。可能有更好的方法来做到这一点,但这就是我的想法,所以你可以:
public class CacheItem
{
public string Identifier { get; set; }
public object Value { get; set; }
public DateTime ValidUntil { get; set; }
public CacheItem(string identifier, object value, TimeSpan valid)
{
Identifier = identifier;
Value = value;
ValidUntil = DateTime.UtcNow.Add(valid);
}
}
缓存存储库
然后我们需要一个类来处理对象并将它们保存在某个地方(如 CacheItem)。我喜欢处理具有后缀 Repository 的类中的所有数据/模型,但您不必,所以让我们构建一个用于缓存。
public class CacheRepository
{
private static Dictionary<string, string> Cache = new Dictionary<string, string>();
private static T Set<T>(string key, Func<T> lookup, TimeSpan durationMinutes)
{
var item = new Models.Item(key, lookup(), durationMinutes);
return Save<T>(key, item);
}
private static T Save<T>(string key, Item item)
{
Cache[key] = JsonConvert.SerializeObject(item);
return (T)item.Value;
}
private static T Get<T>(string key)
{
var cached = Cache.FirstOrDefault(x => x.Key == key).Value;
var item = string.IsNullOrEmpty(cached) ? null : JsonConvert.DeserializeObject<Item>(cached);
return (item == null)
? default : (item.ValidUntil > DateTime.UtcNow)
? JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(item.Value)) : default;
}
public static T GetOrSet<T>(string key, Func<T> lookup, TimeSpan durationMinutes)
{
var cache = Get<T>(key);
return cache == null ? Set(key, lookup, durationMinutes) : cache;
}
}
到目前为止,我们有一个名为 Cache 的静态字典,其中将存储所有项目。请记住,这只会在应用程序运行时持续,因此这个教程标题中有内存缓存。
请记住,一旦加载 CacheRepository 类,Cache 项就会被初始化。
调用 CacheRepository 类时唯一可用的方法是 GetOrSet(string key, Func<T> lookup, TimeSpan durationMinutes),它需要三个参数:
key:要保存的对象的标识符。lookup:缓存过期或为空时的回调函数。durationMinutes:将添加到当前时间(UTC 时间)的持续时间(以分钟为单位)。
缓存时间
现在,使用我们的缓存存储库从某处获取一些数据。
为了使所有这些都有意义,让我们创建一个具有一些属性的示例对象,然后创建一个存储库来获取并填充该对象的列表。
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class UserRepository
{
public List<User> Get()
{
// Code to get users
}
}
由于我们有填充 User 列表的方法,所以让我们使用 CacheRepository 类。
private UserRepository _userRepository = new UserRepository();
private List<User> _user;
public List<User> User
{
get
{
_user = CacheRepository.GetOrSet($"users", usersRepo.Get, TimeSpan.FromMinutes(10));
return _user;
}
}
就像这样,每次访问变量 User 时,它都会向 CacheRepository 询问具有键 users 的对象的值。
如果该密钥存在,它将检查到期日期。如果这些条件之一为 false,它将使用回调来设置对象的值(使用 usersRepo.Get),将其保存到缓存,并将到期日期设置为 DateTime.UtcNow + TimeSpan.FromMinutes(10) 并返回它。
