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"));
}
}
}
Possibly the reason is that Sleep is non-deterministic. It does not pause your thread for 600 milliseconds. It pauses the thread for at least 600 ms. It could very well go over the 1 second sliding expiry you've set without you realising.
This is not, as the other answers have said, due to Thread.Sleep() taking longer than expected.
MemoryCache appears to be pretty imprecise with its sliding timer. I'm guessing that this is so they can avoid locking, and keep up the cache's performance.
So I guess the lesson is to not rely on sliding expirations to work correctly for values under 2 seconds. This may have something to do with the PollingInterval being set to 2 seconds.
Code:
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With