Asp.Net 何时删除过期的缓存项? [英] When Does Asp.Net Remove Expired Cache Items?

查看:24
本文介绍了Asp.Net 何时删除过期的缓存项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当您向 System.Web.Caching.Cache 添加具有绝对到期日期的项目时,如下例所示,Asp.Net 的行为如何?是吗:

  1. 简单地将项目标记为过期,然后在下次访问尝试时执行CacheItemRemovedCallback?

  2. 从缓存中移除项目并立即执行CacheItemRemovedCallback?

    HttpRuntime.Cache.Insert(key,新对象(),空值,DateTime.Now.AddSeconds(seconds),Cache.NoSlidingExpiration,CacheItemPriority.NotRemovable,OnCacheRemove);

MSDN 似乎表明它会立即发生.例如,"ASP.NET 缓存概述" 说ASP.NET 会在项目过期时自动从缓存中删除它们."同样,来自主题 "How to: Notify an Application When an Item is从缓存中删除" 表示如果调用 GetReport [示例中的方法] 之间的时间间隔超过 15 秒,ASP.NET 将从缓存中删除报告."

不过,这些都不是明确的.他们没有说立即执行回调",我可以想象他们的作者可能认为上面的选项 1 算作删除"一个项目.所以我做了一个快速而肮脏的测试,瞧,它似乎立即执行了 - 即使没有人访问我的网站,我也会定期收到 60 秒的回调.

尽管如此,我的测试又快又脏,在我对 有没有办法每天在 .Net web 应用程序中运行一个进程,而无需编写 Windows 服务或 SQL 服务器作业,有人建议 Asp.Net 实际上推迟回调的删除和执行,直到某些东西再次尝试访问缓存.

谁能权威地解决这个问题,或者这只是一个实现细节?

解决方案

Hurray for Reflector!

过期的缓存项实际上被删除(并调用回调)在以下情况下:

1) 有些东西试图访问缓存项.

2) ExpiresBucket.FlushExpiredItems 方法运行并获取项目.此方法被硬编码为每 20 秒执行一次(对 StackOverflow 问题的公认答案 更改 ASP.NET 缓存项到期的频率 证实了我通过 Reflector 对这段代码的阅读).但是,这需要额外的资格(请继续阅读).

<小时>

Asp.Net 为服务器上的每个 CPU 维护一个缓存(我不确定它们是代表逻辑 CPU 还是物理 CPU);每个都维护一个 CacheExpires 实例,该实例具有相应的 Timer,每 20 秒调用一次其 FlushExpiredItems 方法.

此方法依次迭代缓存过期数据的另一个桶"集合(ExpiresBucket 实例的数组),依次调用每个桶的 FlushExpiredItems 方法.>

此方法 (ExpiresBucket.FlushExpiredItems) 首先迭代存储桶中的所有缓存项,如果一项已过期,则将其标记为已过期.然后(我在这里非常简化)它迭代它标记为过期的项目并删除它们,执行CacheItemRemovedCallback(实际上,它调用CacheSingle.Remove,它调用CacheInternal.DoRemove,然后是 CacheSingle.UpdateCache,然后是 CacheEntry.Close,它实际上调用了回调).

所有这些都是连续发生的,所以有可能会阻塞整个过程并阻止事情发生(并将缓存项的到期时间从其指定的到期时间推回).

但是,在此时间分辨率下,最小过期间隔为 20 秒,进程中唯一可能阻塞很长时间的部分是 CacheItemRemovedCallbacks 的执行.其中任何一个都可以想象无限地阻塞给定的 TimerFlushExpiredItems 线程.(虽然 20 秒后,Timer 会产生另一个 FlushExpiredItems 线程.)

总而言之,Asp.Net 不保证它会在指定的时间执行回调,但它会在某些条件下这样做.只要到期间隔相隔超过 20 秒,并且只要缓存不必执行耗时的 CacheItemRemovedCallbacks(全局 - 任何回调都可能干扰任何其他回调),它可以按计划执行到期回调.这对于某些应用程序来说已经足够了,但对于其他应用程序来说就不够用了.

When you add an item to the System.Web.Caching.Cache with an absolute expiration date, as in the following example, how does Asp.Net behave? Does it:

  1. Simply mark the item as expired, then execute the CacheItemRemovedCallback on the next access attempt?

  2. Remove the item from the cache and execute the CacheItemRemovedCallback immediately?

    HttpRuntime.Cache.Insert(key,
                             new object(),
                             null, 
                             DateTime.Now.AddSeconds(seconds), 
                             Cache.NoSlidingExpiration,
                             CacheItemPriority.NotRemovable, 
                             OnCacheRemove);
    

MSDN appears to indicate that it happens immediately. For example, the "Expiration" section of the "ASP.NET Caching Overview" says "ASP.NET automatically removes items from the cache when they expire." Similarly, the example from the topic "How to: Notify an Application When an Item Is Removed from the Cache" says "If more than 15 seconds elapses between calls to GetReport [a method in the example], ASP.NET removes the report from the cache."

Still, neither of these is unambiguous. They don't say "the callback is executed immediately" and I could conceive of how their writers might have thought option 1 above counts as 'removing' an item. So I did a quick and dirty test, and lo, it appears to be executing immediately - I get regular sixty-second callbacks even when no one is accessing my site.

Nonetheless, my test was quick and dirty, and in the comments to my answer to Is there a way to run a process every day in a .Net web application without writing a windows service or SQL server jobs, someone has suggested that Asp.Net actually defers removal and execution of the callback until something tries to access the cache again.

Can anyone settle this authoritatively or is this just considered an implementation detail?

解决方案

Hurray for Reflector!

Expired cache items are actually removed (and callbacks called) when either:

1) Something tries to access the cache item.

2) The ExpiresBucket.FlushExpiredItems method runs and gets to item. This method is hard-coded to execute every 20 seconds (the accepted answer to the StackOverflow question Changing frequency of ASP.NET cache item expiration corroborates my read of this code via Reflector). However, this has needs additional qualification (for which read on).


Asp.Net maintains one cache for each CPU on the server (I'm not sure if it these represent logical or physical CPUs); each of these maintains a CacheExpires instance that has a corresponding Timer that calls its FlushExpiredItems method every twenty seconds.

This method iterates over another collection of 'buckets' of cache expiration data (an array of ExpiresBucket instances) serially, calling each bucket's FlushExpiredItems method in turn.

This method (ExpiresBucket.FlushExpiredItems) first iterates all the cache items in the bucket and if an item is expired, marks it expired. Then (I'm grossly simplifying here) it iterates the items it has marked expired and removes them, executing the CacheItemRemovedCallback (actually, it calls CacheSingle.Remove, which calls CacheInternal.DoRemove, then CacheSingle.UpdateCache, then CacheEntry.Close, which actually calls the callback).

All of that happens serially, so there's a chance something could block the entire process and hold things up (and push the cache item's expiration back from its specified expiration time).

However, at this temporal resolution, with a minimum expiration interval of twenty seconds, the only part of the process that could block for a significant length of time is the execution of the CacheItemRemovedCallbacks. Any one of these could conceivably block a given Timer's FlushExpiredItems thread indefinitely. (Though twenty seconds later, the Timer would spawn another FlushExpiredItems thread.)

To summarize, Asp.Net does not guarantee that it will execute callbacks at the specified time, but it will do so under some conditions. As long as the expiration intervals are more than twenty seconds apart, and as long as the cache doesn't have to execute time-consuming CacheItemRemovedCallbacks (globally - any callbacks could potentially interfere with any others), it can execute expiration callbacks on schedule. That will be good enough for some applications, but fall short for others.

这篇关于Asp.Net 何时删除过期的缓存项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆