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"));
}
}
}
risposta
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.
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. –
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.
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
}
Tutto sul codice, bella domanda! – stephen