Asp.Net 4.0 CacheItemPolicy滑动到期不正确?

时间:2010-10-03 04:11:43

标签: .net-4.0

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.Caching;

using Xunit;

namespace Demo.Caching.Test
{
    class MemoryCacheManagerTest
    {
        [Fact]
        public void Test()
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.SlidingExpiration = TimeSpan.FromSeconds(1);

            MemoryCache.Default.Set("cacheKey4", 4, policy);
            Assert.Equal(4, MemoryCache.Default.Get("cacheKey4"));
            System.Threading.Thread.Sleep(600);
            Assert.Equal(4, MemoryCache.Default.Get("cacheKey4"));
            System.Threading.Thread.Sleep(600);
            Assert.Equal(4, MemoryCache.Default.Get("cacheKey4"));
            // Here I get error
            // Expected: 4, Actual: (null)

            System.Threading.Thread.Sleep(1000);
            Assert.Null(MemoryCache.Default.Get("cacheKey4"));
        }
    }
}

3 个答案:

答案 0 :(得分:4)

可能原因是睡眠是非确定性的。它不会暂停你的线程600毫秒。它暂停的线程至少 600 ms。它可以很好地超过你设定的1秒滑动到期而没有你意识到。

答案 1 :(得分:4)

这是,正如其他答案所说,由于Thread.Sleep()花费的时间超过预期。

滑动计时器

MemoryCache似乎非常不精确。我猜这是他们可以避免锁定,并保持缓存的性能。

  • 如果您将滑动过期时间设置为1秒或更短,则无论访问多少次,缓存项目都会在一秒钟后逐出。
  • 在1到2秒之间,仍然有可能驱逐缓存项目。这可能在一定程度上取决于计算机所处的负载,并且它在很大程度上取决于访问项目的时间,但不像您想象的那样可预测。例如:
    • 如果我将到期时间设置为1.001秒到1.24秒,并且在访问之间休眠200或250毫秒,它会将值保留在缓存中;但如果我睡了201或249毫秒,物品就会被驱逐。
    • 如果我将到期时间设置为1.25秒,我可以在没有问题的情况下长达624毫秒的睡眠时间,但如果我达到625毫秒,那么缓存项目就会被逐出。
  • 一旦达到2秒过期,即使您只在到期截止日期前访问该项目,它似乎也能正常工作。

所以我想我的教训是不要依赖滑动过期来正常工作2秒以下的值。这可能与将PollingInterval设置为2秒有关。

代码:

var span = TimeSpan.FromSeconds(1); // change as necessary
var sw = new Stopwatch();
var cache = new MemoryCache("testcache");
sw.Start();
cache.Add("test", "hello", new CacheItemPolicy{SlidingExpiration = span});
Console.WriteLine(sw.ElapsedMilliseconds);
for (int i = 0; i < 40; i++)
{
    Console.WriteLine(sw.ElapsedMilliseconds + ": " + cache.Get("test"));
    Thread.Sleep(50); // change as necessary
}

答案 2 :(得分:0)

我遇到了同样的问题。但实际上问题是@Colin所说的。 Thread.Sleep正在接管一秒钟。

所以我做了一个更大延迟的测试

[TestMethod]
public void Sliding()
{
    MemoryCache.Default.Add("test", 1,
        new CacheItemPolicy
        {
            SlidingExpiration = new TimeSpan(0, 0, seconds: 5)
        });

    for (int i = 0; i < 15; ++i)
    {
        Assert.IsNotNull(MemoryCache.Default.Get("test"));
        Thread.Sleep(700);
    }
}

它过去了。我不确定它是否会一直有效 - 可能不会 - 但我只是确认滑动确实有效。