ASp .Net Core Web API 中的多个 MemoryCache
Multiple MemoryCache in ASp .Net Core Web API
我有一个 ASP .Net Core 2.2。网页 API。我想通过使用 MemoryCache 来提高性能。但是,我需要缓存 2 种不同的类型,它们都使用整数键。一种是用户列表,另一种是组列表。
现在,我要在 Startup.cs 文件中添加 MemoryCache 服务:
services.AddMemoryCache();
然后我使用依赖注入在两个不同的地方访问这个缓存(在中间件和我写的服务中)。
据我了解,这两个缓存是同一个实例。因此,当我向其中添加我的各种用户和组时,由于它们都有整数键,因此会发生冲突。我该如何处理?我考虑过使用两个缓存 - 每种缓存一个 - 但是(a)我不确定如何做到这一点并且(b)我在某处读到不建议使用多个缓存。有什么想法吗?
是的,我以前遇到过同样的问题,因此我创建了一个扩展版本的 MemoryCache,它允许我插入不同的 "stores".. 你只需将要插入缓存的数据包装成 "metadata" 类型 class 即可。我想类似于 ServiceDescriptors 如何在 DI 中包装您的服务注册?
另外,在具体回答"I thought about using two caches - one for each type"点。这就是问题所在,因为我相信 IMemoryCache 默认注册为单例
我自己 运行 解决了这个问题。我想到的一个解决方案是只在包装器 class 中实例化两个单独的内存缓存,并将包装器 class 注册为单例实例。 但是,只有当您对每个内存缓存有不同的要求时才有意义and/or您希望为每个内存缓存存储大量数据(此时,in-memory缓存可能不是你想要的)。
这是我要缓存的一些示例 classes。
// If using a record, GetHashCode is already implemented through each member already
public record Person(string Name);
// If using a class, ensure that Equals/GetHashCode is overridden
public class Car
{
public string Model { get; }
public Car(string model)
{
Model = model;
}
public override bool Equals(object? obj)
{
return obj is Car car &&
Model == car.Model;
}
public override int GetHashCode()
{
return HashCode.Combine(Model);
}
}
这里是双 MemoryCache 实现。
public class CustomCache : ICustomCache // Expose what you need and register it as singleton instance
{
private readonly MemoryCache personCache;
private readonly MemoryCache carCache;
public CustomCache(IOptions<MemoryCacheOptions> personCacheOptions, IOptions<MemoryCacheOptions> carCacheOptions)
{
personCache = new MemoryCache(personCacheOptions);
carCache = new MemoryCache(carCacheOptions);
}
public void CreatePersonEntry(Person person)
{
_ = personCache.Set(person, person, TimeSpan.FromHours(1));
}
public void CreateCarEntry(Car car)
{
_ = carCache.Set(car, car, TimeSpan.FromHours(12));
}
}
如果您没有上述要求,那么您可以按照 juunas 提到的方法创建一个带有复合键的简单包装器。您仍然需要确保为每个要存储的 class 正确实施 GetHashCode。在这里,我的组合键只是一个整数(我用的是质数,没有具体原因)和一个对象配对。我没有为密钥使用结构,因为 MemoryCache 使用 Dictionary<object, CacheEntry>,所以我不想 box/unbox 密钥。
public class CustomCache : ICustomCache // Expose what you need
{
private readonly IMemoryCache cache;
public CustomCache(IMemoryCache cache)
{
this.cache = cache;
}
public void CreatePersonEntry(Person person)
{
_ = cache.Set(CustomKey.Person(person), person, TimeSpan.FromHours(1));
}
public void CreateCarEntry(Car car)
{
_ = cache.Set(CustomKey.Car(car), car, TimeSpan.FromHours(12));
}
private record CompositeKey(int Key, object Value)
{
public static CustomKey Person(Person value) => new(PERSON_KEY, value);
public static CustomKey Car(Car value) => new(CAR_KEY, value);
private const int PERSON_KEY = 1123322689;
private const int CAR_KEY = 262376431;
}
}
如果您发现任何错误或有更好的解决方案,请告诉我。
我有一个 ASP .Net Core 2.2。网页 API。我想通过使用 MemoryCache 来提高性能。但是,我需要缓存 2 种不同的类型,它们都使用整数键。一种是用户列表,另一种是组列表。
现在,我要在 Startup.cs 文件中添加 MemoryCache 服务:
services.AddMemoryCache();
然后我使用依赖注入在两个不同的地方访问这个缓存(在中间件和我写的服务中)。
据我了解,这两个缓存是同一个实例。因此,当我向其中添加我的各种用户和组时,由于它们都有整数键,因此会发生冲突。我该如何处理?我考虑过使用两个缓存 - 每种缓存一个 - 但是(a)我不确定如何做到这一点并且(b)我在某处读到不建议使用多个缓存。有什么想法吗?
是的,我以前遇到过同样的问题,因此我创建了一个扩展版本的 MemoryCache,它允许我插入不同的 "stores".. 你只需将要插入缓存的数据包装成 "metadata" 类型 class 即可。我想类似于 ServiceDescriptors 如何在 DI 中包装您的服务注册?
另外,在具体回答"I thought about using two caches - one for each type"点。这就是问题所在,因为我相信 IMemoryCache 默认注册为单例
我自己 运行 解决了这个问题。我想到的一个解决方案是只在包装器 class 中实例化两个单独的内存缓存,并将包装器 class 注册为单例实例。 但是,只有当您对每个内存缓存有不同的要求时才有意义and/or您希望为每个内存缓存存储大量数据(此时,in-memory缓存可能不是你想要的)。
这是我要缓存的一些示例 classes。
// If using a record, GetHashCode is already implemented through each member already
public record Person(string Name);
// If using a class, ensure that Equals/GetHashCode is overridden
public class Car
{
public string Model { get; }
public Car(string model)
{
Model = model;
}
public override bool Equals(object? obj)
{
return obj is Car car &&
Model == car.Model;
}
public override int GetHashCode()
{
return HashCode.Combine(Model);
}
}
这里是双 MemoryCache 实现。
public class CustomCache : ICustomCache // Expose what you need and register it as singleton instance
{
private readonly MemoryCache personCache;
private readonly MemoryCache carCache;
public CustomCache(IOptions<MemoryCacheOptions> personCacheOptions, IOptions<MemoryCacheOptions> carCacheOptions)
{
personCache = new MemoryCache(personCacheOptions);
carCache = new MemoryCache(carCacheOptions);
}
public void CreatePersonEntry(Person person)
{
_ = personCache.Set(person, person, TimeSpan.FromHours(1));
}
public void CreateCarEntry(Car car)
{
_ = carCache.Set(car, car, TimeSpan.FromHours(12));
}
}
如果您没有上述要求,那么您可以按照 juunas 提到的方法创建一个带有复合键的简单包装器。您仍然需要确保为每个要存储的 class 正确实施 GetHashCode。在这里,我的组合键只是一个整数(我用的是质数,没有具体原因)和一个对象配对。我没有为密钥使用结构,因为 MemoryCache 使用 Dictionary<object, CacheEntry>,所以我不想 box/unbox 密钥。
public class CustomCache : ICustomCache // Expose what you need
{
private readonly IMemoryCache cache;
public CustomCache(IMemoryCache cache)
{
this.cache = cache;
}
public void CreatePersonEntry(Person person)
{
_ = cache.Set(CustomKey.Person(person), person, TimeSpan.FromHours(1));
}
public void CreateCarEntry(Car car)
{
_ = cache.Set(CustomKey.Car(car), car, TimeSpan.FromHours(12));
}
private record CompositeKey(int Key, object Value)
{
public static CustomKey Person(Person value) => new(PERSON_KEY, value);
public static CustomKey Car(Car value) => new(CAR_KEY, value);
private const int PERSON_KEY = 1123322689;
private const int CAR_KEY = 262376431;
}
}
如果您发现任何错误或有更好的解决方案,请告诉我。