SlidingExpiration和MemoryCache

查看MemoryCache的文档,我预计如果在Expiration期间访问了一个对象,则会刷新该期间。 说实话,我认为我从“滑动”这个名称中推断出任何东西。

但是,从这个测试看来

[Test] public void SlidingExpiryNotRefreshedOnTouch() { var memoryCache = new MemoryCache("donkey") { { "1", "jane", new CacheItemPolicy {SlidingExpiration = TimeSpan.FromSeconds(1) } } }; var enumerable = Enumerable.Repeat("1", 100) .TakeWhile((id, index) => { Thread.Sleep(100); return memoryCache.Get(id) != null; // ie it still exists }) .Select((id, index) => (index+2)*100.0/1000); // return the elapsed time var expires = enumerable.Last(); // gets the last existing entry expires.Should().BeGreaterThan(1.0); } 

它失败并显示一旦TimeSpan完成后对象被弹出的行为,无论对象是否已被访问。 Linq查询在enumerable.Last(); 语句,此时缓存尚未过期。 一旦停止,列表中的最后一项将指示项目在缓存中存在多长时间。

对于Clarity这个问题是关于MemoryCache的行为。 不是linq查询。

这是否是其他人的期望(即每次触摸时到期时间不会滑动)? 是否有一种模式可以延长“触摸”对象的生命周期?

更新我发现即使我在缓存周围写了一个包装器,并且每次检索它时都将对象重新添加回缓存,而另一个SlidingExpiration仍然只支持初始设置。 为了让它以我想要的方式工作,我必须在重新添加它之前将其从缓存中移除! 这可能在multithreading环境中导致不期望的竞争条件。

  ... new CacheItemPolicy {SlidingExpiration = TimeSpan.FromSeconds(1) } 

这在MSDN中没有充分记录。 你有点不走运,1秒还不够。 通过头发,使用2秒,你会看到它的工作方式就像你希望的那样。 使用FromMilliseconds()修补更多内容,你会发现~1.2秒是这个程序中最快的最小值。

解释这个问题相当复杂,我不得不谈谈MemoryCache如何避免每次访问缓存时都必须更新滑动计时器。 正如您可能想象的那样,这是相对昂贵的。 让我们走捷径,带您到相关的参考源代码 。 小到足以粘贴在这里:

  internal void UpdateSlidingExp(DateTime utcNow, CacheExpires expires) { if (_slidingExp > TimeSpan.Zero) { DateTime utcNewExpires = utcNow + _slidingExp; if (utcNewExpires - _utcAbsExp >= CacheExpires.MIN_UPDATE_DELTA || utcNewExpires < _utcAbsExp) { expires.UtcUpdate(this, utcNewExpires); } } } 

CacheExpires.MIN_UPDATE_DELTA是关键,它阻止调用UtcUpdate()。 换句话说,至少MIN_UPDATE_DELTA值的时间必须通过才会更新滑动计时器。 CacheExpired类没有被Reference Source索引,暗示他们对它的工作方式并不完全满意:)但是一个体面的反编译器可以告诉你:

 static CacheExpires() { MIN_UPDATE_DELTA = new TimeSpan(0, 0, 1); MIN_FLUSH_INTERVAL = new TimeSpan(0, 0, 1); // etc... } 

换句话说,硬编码为1秒。 现在无法改变它,这非常难看。 此测试程序中的SlidingExpiration值需要大约1.2秒,因为Thread.Sleep(100)实际上不会hibernate100毫秒,需要更多时间。 换句话说,它将是第11次Get()调用,它使滑动计时器在此测试程序中滑动。 你没那么远。

嗯,这应该记录在案,但我猜这可能会有所改变。 现在,您需要假设一个实际的滑动到期时间应该至少为2秒。