如EhCache文档中所述:
实际上,这意味着持久的内存缓存将启动磁盘上的所有元素.[...]因此,Ehcache设计在启动时不会将它们全部加载到内存中,而是根据需要懒洋洋地加载它们.
我想内存缓存启动将其所有元素都存储在内存中,我该如何实现呢?
原因是我们的网站对缓存执行了大量访问,因此我们第一次访问网站时响应时间非常短.
编辑 有关其他详细信息,请参阅问题底部的编辑注释.
原始问题
我有一个CacheWrapper类,它在MemoryCache内部创建并保存在.NET 类的实例上.
MemoryCache将自己挂钩到AppDomain事件中,因此除非明确处理,否则它永远不会被垃圾收集.您可以使用以下代码进行验证:
Func<bool, WeakReference> create = disposed => {
var cache = new MemoryCache("my cache");
if (disposed) { cache.Dispose(); }
return new WeakReference(cache);
};
// with false, we loop forever. With true, we exit
var weakCache = create(false);
while (weakCache.IsAlive)
{
"Still waiting...".Dump();
Thread.Sleep(1000);
GC.Collect();
GC.WaitForPendingFinalizers();
}
"Cleaned up!".Dump();
Run Code Online (Sandbox Code Playgroud)
由于这种行为,我认为我的MemoryCache实例应该被视为非托管资源.换句话说,我应该确保它被放置在CacheWrapper的终结器中(CacheWrapper本身是Disposable遵循标准的Dispose(bool)模式).
但是,当我的代码作为ASP.NET应用程序的一部分运行时,我发现这会导致问题.卸载应用程序域时,终结器将在我的CacheWrapper类上运行.这反过来试图处理该MemoryCache实例.这是我遇到问题的地方.似乎Dispose试图从IIS加载一些配置信息失败(大概是因为我正在卸载app域,但我不确定.这是我的堆栈转储:
MANAGED_STACK:
SP IP Function
000000298835E6D0 0000000000000001 System_Web!System.Web.Hosting.UnsafeIISMethods.MgdGetSiteNameFromId(IntPtr, UInt32, IntPtr ByRef, Int32 ByRef)+0x2
000000298835E7B0 000007F7C56C7F2F System_Web!System.Web.Configuration.ProcessHostConfigUtils.GetSiteNameFromId(UInt32)+0x7f
000000298835E810 000007F7C56DCB68 System_Web!System.Web.Configuration.ProcessHostMapPath.MapPathCaching(System.String, …Run Code Online (Sandbox Code Playgroud) 在ASP.NET Core中,它很容易从控制器访问您的内存缓存
在你的创业公司中你添加:
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
}
Run Code Online (Sandbox Code Playgroud)
然后从你的控制器
[Route("api/[controller]")]
public class MyExampleController : Controller
{
private IMemoryCache _cache;
public MyExampleController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
[HttpGet("{id}", Name = "DoStuff")]
public string Get(string id)
{
var cacheEntryOptions = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromHours(1));
_cache.Set("key", "value", cacheEntryOptions);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如何在控制器外部访问相同的内存缓存.例如.我有一个由HangFire发起的计划任务,如何从我的代码中通过HangFire计划任务访问内存缓存?
public class ScheduledStuff
{
public void RunScheduledTasks()
{
//want to access the same memorycache here ...
}
}
Run Code Online (Sandbox Code Playgroud) So this all worked fine before updating to AspNetCore 3 today.
I am using a memory cache with dependency injection (IMemoryCache cache).
I add it to my middleware with services.AddMemoryCache();
and do NOT set a size, but I still end up with the error message:
Cache entry must specify a value for Size when SizeLimit is set.
When I inspect the instance of MemoryCache and it does indeed have a size of 10240 set (see image).
问题是我已经找了一个小时,我不知道这是在哪里设置的。我的代码中没有任何地方SizeLimit …
我有以下问题,我有这种缓存管理:
public class CacheManager : ICacheManager {
private readonly ObjectCache cache;
public CacheManager() {
this.cache = MemoryCache.Default;
}
public void AddItem(string key, object itemToCache, double duration) {
var end = DateTime.Now.AddSeconds(duration);
this.cache.Add(key, itemToCache, end);
}
public T Get<T>(string key) where T : class {
try {
return (T)this.cache[key];
}
catch (Exception ex) {
return null;
}
}
public void Remove(string key) {
this.cache.Remove(key);
}
}
Run Code Online (Sandbox Code Playgroud)
很简单。
编辑我(问题文本中的错误修复)
问题:当任何键的缓存过期时,获取缓存中任何对象的所有以下调用都会返回“null”。我检查了按键并且总是正确的。
该问题仅出现在我的 PC 中的客户端服务器中,并且我的服务器工作正常。
谢谢。
编辑二(前进)
当我们重新启动客户服务器中的应用程序池时,您的问题在几个小时内得到了解决。
我们的网站有一个特定的应用程序池,具有以下设置:
Pipeline Manager 模式:集成框架:v4.0 启用 32 …
我MemoryCache用来在我的MVC .Net应用程序中存储键/值对.
我使用的主要目的有两个MemoryCache.一个是存储用户id的会话,另一个是存储常量(这只是一个例子)理论上两个键在两种情况下都是相同的,所以我想用一些方法来分离这两个.
我想2或3种方法.哪种方式优越?还是有更好的选择吗?
缓存中的每个键都将由命名空间添加.
"user_session:1","user_session:2"
"常量:1","常量:2"
使用嵌套字典作为键.
将有一个键"user_sessions",其值将是一个将id映射到会话对象的Dictionary.将有一个关键的"常量",其值将是一个字典.
每个"命名空间"都有自己的MemoryCache实例.
#2的缺点是,当我想获取属于用户ID的值时,我需要首先获取字典,然后获取该字典中的键的值.这意味着我需要将字典存储在内存中.
IE:
Dictionary<string, string> userSessions = MemoryCache.Default["user_sessions"]
object session = userSessions.get("1");
Run Code Online (Sandbox Code Playgroud) 我IMemoryCache在我的项目中使用.我想知道如果我的应用程序在缓存中推送许多长生命对象会发生什么.它可以占用所有可用的内存吗?我可以全局定义应用程序的最大内存吗?
我在Microsoft.Extensions.Caching.Memory.MemoryCache中设置了具有滑动过期的缓存项.我想在每次缓存项到期时触发回调,但在我查询缓存中过期的缓存项之前,不会触发回调.
这是代码:
using System;
using Microsoft.Extensions.Caching.Memory;
namespace Memcache
{
public class Program
{
private static MemoryCache _cache;
private static int _cacheExpSecs;
public static void Main(string[] args)
{
_cache = new MemoryCache(new MemoryCacheOptions());
_cacheExpSecs = 2;
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(_cacheExpSecs))
.RegisterPostEvictionCallback(callback: EvictionCallback);
_cache.Set(1, "One", cacheEntryOptions);
_cache.Set(2, "Two", cacheEntryOptions);
var autoEvent = new System.Threading.AutoResetEvent(false);
System.Threading.Timer timer = new System.Threading.Timer(checkCache, autoEvent, 1000, 6000);
Console.Read();
}
private static void checkCache(Object o)
{
if(_cache.Get(1)!=null)
{
Console.WriteLine(string.Format(@"checkCache: Cache with key {0} will be removed …Run Code Online (Sandbox Code Playgroud) 我正在使用 来IMemoryCache缓存从身份服务器检索到的令牌。
过去我使用过库GetOrCreateAsync中提供的扩展方法Microsoft.Extensions.Caching.Abstractions。这非常有帮助,因为我可以同时定义函数和到期日期。
但是,使用令牌时,在请求完成之前我不会知道x 秒后的过期值。我想通过根本不缓存令牌来解释不存在的值的用例。
我尝试过以下方法
var token = await this.memoryCache.GetOrCreateAsync<string>("SomeKey", async cacheEntry =>
{
var jwt = await GetTokenFromServer();
var tokenHasValidExpireValue = int.TryParse(jwt.ExpiresIn, out int tokenExpirationSeconds);
if (tokenHasValidExpireValue)
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(tokenExpirationSeconds);
}
else // Do not cache value. Just return it.
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(0); //Exception thrown. Value needs to be positive.
}
return jwt.token;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,当我尝试设置 no time 过期时,会引发异常TimeSpan.FromSeconds(0)。
除了分别调用Get和Set方法之外,还有其他方法可以解决这个问题吗?如果可能的话我想使用该GetOrCreateAsync方法。
应用程序需要加载数据并缓存一段时间。我希望如果应用程序的多个部分想要同时访问同一个缓存键,缓存应该足够智能,只加载一次数据并将该调用的结果返回给所有调用者。然而,MemoryCache并不是这样做的。如果您并行访问缓存(这通常发生在应用程序中),它会为每次尝试获取缓存值创建一个任务。我认为这段代码会达到预期的结果,但事实并非如此。我希望缓存只运行一项GetDataAsync任务,等待它完成,然后使用结果来获取其他调用的值。
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ConsoleApp4
{
class Program
{
private const string Key = "1";
private static int number = 0;
static async Task Main(string[] args)
{
var memoryCache = new MemoryCache(new MemoryCacheOptions { });
var tasks = new List<Task>();
tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
await Task.WhenAll(tasks);
Console.WriteLine($"The cached value was: {memoryCache.Get(Key)}");
}
public static async Task<int> GetDataAsync()
{
//Simulate getting a large …Run Code Online (Sandbox Code Playgroud) memorycache ×10
c# ×6
asp.net-core ×4
.net ×3
asp.net ×3
.net-core ×2
asp.net-mvc ×2
caching ×2
asynchronous ×1
concurrency ×1
ehcache ×1
finalizer ×1
idisposable ×1
iis ×1
java ×1