如何从C#Web API REST服务器缓存缓慢的资源初始化?
上下文 我正在尝试实现一个RESTAPI web服务,它“包装”了一个现有的C程序 问题/目标 考虑到当我告诉C程序打开一个特定的文件夹时,它的初始化时间慢,RAM使用率高(假设这无法改进),我考虑缓存C句柄/对象,因此下次GET请求命中同一文件夹时,我可以使用现有的句柄 我尝试过的 首先声明从文件夹路径到句柄的静态字典映射:如何从C#Web API REST服务器缓存缓慢的资源初始化?,c#,rest,caching,asp.net-web-api,C#,Rest,Caching,Asp.net Web Api,上下文 我正在尝试实现一个RESTAPI web服务,它“包装”了一个现有的C程序 问题/目标 考虑到当我告诉C程序打开一个特定的文件夹时,它的初始化时间慢,RAM使用率高(假设这无法改进),我考虑缓存C句柄/对象,因此下次GET请求命中同一文件夹时,我可以使用现有的句柄 我尝试过的 首先声明从文件夹路径到句柄的静态字典映射: static ConcurrentDictionary<string, IHandle> handles = new ConcurrentDictionary
static ConcurrentDictionary<string, IHandle> handles = new ConcurrentDictionary<string, IHandle>();
这样一来,每当以前获得某个特定文件夹时,它就已经有了一个句柄,可以供我使用
为什么不好
因此,如果同时缓存了太多的文件夹,我就有内存不足的风险。如何将类似GC的后台进程添加到TryRemove()
中,并在旧句柄上调用IHandle.Dispose()
,可能是在最近使用最少或使用最少的策略中?理想情况下,它应该仅在可用物理内存不足时启动触发
我曾尝试在GET函数中添加以下语句,但它似乎太粗糙,并且在函数中非常有限。只有当我总是希望句柄在10秒后过期时,这种方法才可以正常工作,并且如果后续请求在10秒内传入,它不会重新启动计时器
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
System.Threading.Thread.Sleep(10000);
if (handles.TryRemove(dir.Name, out var handle2))
handle2.Dispose();
});
这个问题不是什么
我不认为缓存输出是这里的解决方案。在我返回这个GET请求的结果(它只是文件夹内容的元数据)之后,可能会有另一个GET请求来获取更深入的数据,这需要调用Handle
的方法
我希望我的问题足够清楚
ConcurrentQueue句柄=新建ConcurrentQueue();
void CheckMemory_optionalReleaseOldHandles()
{
var performance=新系统.诊断.性能计数器(“内存”,“可用MB”);
while(performance.NextValue()v.Item1==dir.Name).Item2;
if(theHandle==null)
{
theHandle=新句柄(目录名);
handles.Enqueue((dir.Name,theHandle));
}
返回手柄;
});
void SetupMemoryCheck()
{
检查记忆=ct=>
{
对于(;;)
{
如果(ct.IsCancellationRequested)
{
打破
}
选中Memory_OptionalReleaseOldHandles();
睡眠(500);
};
};
HostingEnvironment.QueueBackgroundWorkItem(ct=>
{
var tf=新TaskFactory(ct、TaskCreationOptions.LongRunning、TaskContinuationOptions.None、TaskScheduler.Current);
tf.StartNew(()=>正在检查内存(ct));
});
}
我想这个系列会有一些元素,所以不需要查字典。我第一次没注意到你的LRU/LFU需求。在这里,您可以检查一些混合LRU/LFU缓存模型
/*
*string–句柄名称,
*IHandle–手柄,
*int–命中计数,
*/
ConcurrentDictionary句柄=新建ConcurrentDictionary();
无效免费资源()
{
if(handles.Count==0)
{
返回;
}
var performance=新系统.诊断.性能计数器(“内存”,“可用MB”);
while(performance.NextValue()
{
对于(;;)
{
如果(ct.IsCancellationRequested)中断;
免费资源();
睡眠(500);
}
};
HostingEnvironment.QueueBackgroundWorkItem(ct=>
{
新任务(()=>BeCheckingTheMemory(ct),TaskCreationOptions.LongRunning.Start();
});
}
如果您希望收集大量的for循环,则可以对其进行优化。您说过响应只包含文件夹元数据?是否需要文件夹(元数据)经常更改?为什么不只缓存元数据?正如我问题的最后一部分所述,可能还有一个获取更详细数据的GET请求,因此我需要将句柄保存在内存中,而不仅仅是元数据。我现在读到了。如果详细请求会出现,是否仍然需要将句柄保持打开状态?可以有任意数量的后续de尾部请求。保持句柄打开可以让我非常快速地响应这些详细请求。因为可能有太多不同的输出,所以不可能缓存详细请求。我希望尽可能长时间地保持句柄,直到物理内存变低,然后我释放它们,希望是以LRU/LFU方式。我没有这样做“我第一次没有注意到你的LRU/LFU需求。你还对它感兴趣吗?我还意识到你的代码可能仍然容易受到OutOfMemoryException的攻击。这会影响你的\u TRESHHOLD和最大的文件期望比率,以及请求方式。会有同时的请求吗?请求会多久出现一次?我还意识到没有必要。”o定期检查内存级别。如果内存级别出现异常,可以在处理负载时进行检查。这将一举两得
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
System.Threading.Thread.Sleep(10000);
if (handles.TryRemove(dir.Name, out var handle2))
handle2.Dispose();
});