当您使用绝对截止日期向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算作“删除”一个项目。所以我做了一个快速而肮脏的测试,而且,它似乎立即执行 - 即使没有人访问我的网站,我也会定期进行第六十二次回调。
尽管如此,我的测试很快而且很脏,在我对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实际上推迟删除和执行回调,直到某些东西试图再次访问缓存。
任何人都可以权威地解决这个问题,还是仅仅考虑实施细节?
答案 0 :(得分:37)
Hurray for 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
,然后{{ 1}},然后是CacheSingle.UpdateCache
,它实际上调用了回调函数。)
所有这些都是连续发生的,因此有可能阻止整个过程并保持原状(并将缓存项目的到期时间从指定的到期时间推回)。
但是,在此时间分辨率下,最小到期间隔为20秒,可能阻塞相当长时间的过程的唯一部分是执行CacheEntry.Close
。其中任何一个都可以无限制地阻止给定CacheItemRemovedCallbacks
的{{1}}线程。 (虽然20秒后,Timer
会产生另一个FlushExpiredItems
线程。)
总而言之,Asp.Net不保证它将在指定时间执行回调,但它会在某些条件下执行回调。只要到期时间间隔超过20秒,并且只要缓存不必执行耗时Timer
(全局 - 任何回调可能会干扰其他任何回调),它就可以执行到期如期回调。对于某些应用程序来说这已经足够了,但对其他应用程序来说却是不够的。
答案 1 :(得分:5)
过期的项目不会立即从缓存中删除,它们只是标记为已过期。在缓存未命中之前,您不会收到回调。我在ASP.NET 1.1天{@ 3}}中遇到了这个问题。
可能会出现立即删除过期项目的情况 - 例如内存不足和CPU过高 - 但您无法指望它。
我通常使用一个定期重新加载缓存的计时器。