当您将一个具有绝对到期日期的项目添加到System.Web.Caching.Cache
中时,如以下示例所示,Asp.Net的行为如何?可以:
CacheItemRemovedCallback
? CacheItemRemovedCallback
吗?HttpRuntime.Cache.Insert(key,
new object(),
null,
DateTime.Now.AddSeconds(seconds),
Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable,
OnCacheRemove);
MSDN似乎表明它立即发生。例如,the "Expiration" section of the "ASP.NET Caching Overview"说“ASP.NET在过期时会自动从缓存中删除它们”。同样,主题"How to: Notify an Application When an Item Is Removed from the Cache"中的示例说:“如果两次调用
GetReport
(示例中的方法)之间的时间间隔超过15秒,则ASP.NET将从缓存中删除报告。”尽管如此,这些都不是明确的。他们不会说“回调会立即执行”,我可以想象他们的作者可能如何认为上述选项1被视为“删除”了一项。因此,我进行了一次快速而肮脏的测试,瞧,它似乎立即开始执行-即使没有人访问我的网站,我也会得到定期的60秒回调。
但是,我的测试又快又脏,在有人回答Is there a way to run a process every day in a .Net web application without writing a windows service or SQL server jobs的评论中,有人建议Asp.Net实际上推迟了回调的删除和执行,直到某些东西试图再次访问缓存为止。
任何人都可以权威地解决这个问题,或者这仅仅是实现细节?
最佳答案
为Reflector欢呼!
发生以下情况时,实际上将删除过期的缓存项(并调用回调):
1)某些东西试图访问缓存项。
2)ExpiresBucket.FlushExpiredItems
方法运行并转到项目。此方法被硬编码为每20秒执行一次(已接受的StackOverflow问题Changing frequency of ASP.NET cache item expiration答案证实了我通过Reflector对该代码的读取)。但是,这需要附加的限定条件(请继续阅读)。
Asp.Net为服务器上的每个CPU维护一个缓存(我不确定它们是否代表逻辑或物理CPU)。每个实例都维护一个CacheExpires
实例,该实例具有一个对应的Timer
,每20秒调用一次FlushExpiredItems
方法。
此方法依次迭代缓存过期数据的另一个“桶”集合(一个ExpiresBucket
实例数组),依次调用每个桶的FlushExpiredItems
方法。
此方法(ExpiresBucket.FlushExpiredItems
)首先迭代存储桶中的所有缓存项目,如果某个项目已过期,则将其标记为已过期。然后(在这里我要简化),迭代它标记为已过期的项目并删除它们,执行CacheItemRemovedCallback
(实际上,它调用CacheSingle.Remove
,后者先调用CacheInternal.DoRemove
,然后再调用CacheSingle.UpdateCache
,然后再调用CacheEntry.Close
,而后者实际上会调用回调)。
所有这些都是串行发生的,因此有可能会阻塞整个过程并阻止事情(并从指定的过期时间推迟缓存项的过期)。
但是,在此时间分辨率下,以20秒的最小到期时间间隔,可能会阻塞相当长的时间长度的过程的唯一部分是CacheItemRemovedCallbacks
的执行。这些中的任何一个都可以无限期地阻塞给定的Timer
的FlushExpiredItems
线程。 (尽管二十秒后,Timer
会生成另一个FlushExpiredItems
线程。)
总而言之,Asp.Net不保证它将在指定的时间执行回调,但是在某些情况下会这样做。只要到期间隔相隔二十秒以上,并且只要高速缓存不必执行耗时的CacheItemRemovedCallbacks
(全局-任何回调都可能会干扰其他任何回调),它就可以按计划执行到期回调。对于某些应用程序来说这已经足够了,但对于其他应用程序却不够。
关于asp.net - Asp.Net何时删除过期的缓存项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1434284/