2010-10-03 17 views
8
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")); 
     } 
    } 
} 
+0

Todo sobre el código, buena pregunta! – stephen

Respuesta

4

Posiblemente la razón es que Sleep no es determinista. No pausa su hilo durante 600 milisegundos. Pausa el hilo para al menos 600 ms. Podría muy bien superar el vencimiento deslizante de 1 segundo que ha configurado sin que se dé cuenta.

+0

vea también la respuesta de @StripplingWarrior sobre 'PollingInterval'. El truco parece ser que los retrasos por debajo del intervalo de sondeo se tratan de forma imprecisa. –

0

Tuve el mismo problema. Pero en realidad el problema es lo que dijo @Colin. El Thread.Sleep está tardando más de un segundo.

así que hice una prueba con un retraso grande

[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); 
    } 
} 

y pasó. No estoy seguro si siempre funcionará, probablemente no, pero confirmó que el deslizamiento realmente funciona.

4

Esto es no, como han dicho las otras respuestas, debido a que Thread.Sleep() tarda más de lo esperado.

MemoryCache parece ser bastante impreciso con su temporizador deslizante. Supongo que esto es para que puedan evitar el bloqueo y mantener el rendimiento del caché.

  • Si establece un plazo de caducidad de 1 segundo o menos, los elementos de la caché será desalojado después de un segundo, independientemente de cuántas veces se accede a ellos.
  • Entre 1 y 2 segundos, todavía parece haber una posibilidad de expulsar los elementos de la memoria caché. Esto puede depender en cierta medida de la carga en la que se encuentre la computadora, y definitivamente depende en gran medida de cuándo se accede a los elementos, pero no tan predeciblemente como se podría pensar. Por ejemplo:
    • si establezco la caducidad en cualquier lugar desde 1.001 segundos a 1.24 segundos, y duermo durante 200 o 250 milisegundos entre accesos, mantiene el valor en la caché; pero si duermo durante 201 o 249 milisegundos, el objeto es desalojado.
    • si configuro la caducidad en 1.25 segundos, puedo dormir hasta 624 milisegundos sin problema, pero si pulso 625 milisegundos, el elemento de caché queda desalojado.
  • Una vez que llegue a un vencimiento de 2 segundos, parece funcionar correctamente incluso si solo accede al elemento una vez, justo antes de la fecha límite de vencimiento.

Así que supongo que la lección es no confiar en que las expiraciones deslizantes funcionen correctamente para valores inferiores a 2 segundos. Esto puede tener algo que ver con el ajuste PollingInterval en 2 segundos.

Código:

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 
} 
Cuestiones relacionadas