2010-10-03 16 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

Tutto sul codice, bella domanda! – stephen

risposta

4

Forse la ragione è che il sonno non è deterministico. Non mette in pausa il thread per 600 millisecondi. Mette in pausa la discussione per almeno 600 ms. Potrebbe benissimo superare la scadenza di 1 secondo che hai impostato senza che te ne rendessi conto.

+0

vedere anche la risposta di @StripplingWarrior su 'PollingInterval'. Il trucco sembra essere che i ritardi al di sotto dell'intervallo di polling sono trattati in modo impreciso. –

0

Ho avuto lo stesso problema. Ma in realtà il problema è quello che ha detto @Colin. Il Thread.Sleep sta prendendo più di un secondo.

così ho fatto un test con un ritardo maggiore

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

Ed è passato. Non sono sicuro che funzionerà sempre, probabilmente no, ma ho appena confermato che lo scorrimento funziona davvero.

4

Questo è non, come le altre risposte hanno detto, a causa di Thread.Sleep() che richiede più tempo del previsto.

MemoryCache sembra essere piuttosto impreciso con il suo timer scorrevole. Immagino che sia così che possano evitare il blocco e mantenere le prestazioni della cache.

  • Se si imposta una scadenza di scorrimento di 1 secondo o meno, gli elementi della cache verranno eliminati dopo un secondo indipendentemente dal numero di accessi.
  • Tra 1 e 2 secondi, sembra che ci sia ancora una possibilità di sfrattare gli elementi della cache. Ciò può dipendere in qualche modo dal carico del computer e dipende in gran parte dal momento in cui si accede agli oggetti, ma non in modo prevedibile come si penserebbe. Ad esempio:
    • se si imposta la scadenza su qualsiasi valore compreso tra 1.001 secondi e 1.24 secondi e si sospende per 200 o 250 millisecondi tra gli accessi, mantiene il valore nella cache; ma se dormo per 201 o 249 millisecondi, l'oggetto viene sfrattato.
    • se imposto la scadenza a 1,25 secondi, posso dormire fino a 624 millisecondi senza problemi, ma se colpisco 625 millisecondi, l'elemento della cache viene rimosso.
  • Una volta raggiunta la scadenza di 2 secondi, sembra che funzioni correttamente anche se si accede all'elemento solo una volta, immediatamente prima della scadenza.

Quindi suppongo che la lezione è di non fare affidamento sulle scadenze di scorrimento per funzionare correttamente per valori inferiori a 2 secondi. Ciò potrebbe avere a che fare con lo PollingInterval impostato su 2 secondi.

Codice:

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 
} 
Problemi correlati