2009-09-16 10 views
19

Quando si aggiunge un articolo allo System.Web.Caching.Cache con una data di scadenza assoluta, come nell'esempio seguente, come si comporta Asp.Net? Lo fa:Quando Asp.Net rimuove gli elementi della cache scaduti?

  1. È sufficiente contrassegnare l'elemento come scaduto, quindi eseguire il CacheItemRemovedCallback al successivo tentativo di accesso?

  2. Rimuovere l'elemento dalla cache ed eseguire immediatamente lo CacheItemRemovedCallback?

    HttpRuntime.Cache.Insert(key, 
             new object(), 
             null, 
             DateTime.Now.AddSeconds(seconds), 
             Cache.NoSlidingExpiration, 
             CacheItemPriority.NotRemovable, 
             OnCacheRemove); 
    

MSDN sembra indicare che avviene immediatamente. Ad esempio, the "Expiration" section of the "ASP.NET Caching Overview" dice "ASP.NET rimuove automaticamente gli elementi dalla cache quando scadono." Analogamente, l'esempio dell'argomento "How to: Notify an Application When an Item Is Removed from the Cache" dice "Se trascorrono più di 15 secondi tra le chiamate a GetReport [un metodo nell'esempio], ASP.NET rimuove il report dalla cache."

Tuttavia, nessuno di questi è univoco. Non dicono "la richiamata viene eseguita immediatamente" e potrei pensare a come i loro scrittori potrebbero aver pensato che l'opzione 1 di cui sopra conta come "rimuovere" un oggetto. Così ho fatto un test rapido e sporco, e ecco, sembra che si stia eseguendo immediatamente - ricevo regolarmente callback di sessanta secondi anche quando nessuno accede al mio sito.

Tuttavia, il mio test era veloce e sporco, e nei commenti alla mia risposta a Is there a way to run a process every day in a .Net web application without writing a windows service or SQL server jobs, qualcuno ha suggerito che Asp.Net in realtà rimuove la rimozione e l'esecuzione del callback fino a quando qualcosa tenta di accedere nuovamente alla cache.

Qualcuno può risolvere questo autorevolmente o è solo considerato un dettaglio di implementazione?

+2

Non penso che ci possa essere una risposta autorevole a questa domanda perché, come a Raymond Chen piace tanto sottolineare, si interpreta il comportamento di una versione del software come autorevole per tutte le versioni future. Nella mia esperienza questa è una cattiva idea in quanto ASP.NET potrebbe cambiare il suo comportamento in qualsiasi momento e rompere la tua applicazione. – dkackman

+1

perché non lo provi. Sul callback scrivi su un file e vedi la data di creazione e come si riferisce alla scadenza. –

+0

@dkackman - Non ho bisogno di una risposta "ora e per sempre", sono disposto ad accontentarmi di risposte autorevoli per .NET 2.0 e 3.5. Non mi sembra proprio un dettaglio di implementazione: mi aspetterei che la documentazione dicesse da qualche parte che la rimozione effettiva non è deterministica se così fosse. Forse la MS non è d'accordo. Sto solo cercando di vedere se ho appena trascurato qualcosa nella documentazione. –

risposta

35

Evviva per Reflector!

elementi della cache scaduti sono realtà rimosso (e callback chiamata) quando:

1) Qualcosa tenta di accedere alla voce di cache.

2) Il metodo ExpiresBucket.FlushExpiredItems viene eseguito e arriva all'elemento. Questo metodo è codificato per l'esecuzione ogni 20 secondi (la risposta accettata alla domanda StackOverflow Changing frequency of ASP.NET cache item expiration conferma la lettura di questo codice tramite Reflector). Tuttavia, questo ha bisogno di ulteriori qualifiche (per le quali leggere).


Asp.Net mantiene una cache per ogni CPU sul server (non sono sicuro se questi rappresentano CPU logico o fisico); ognuno di questi gestisce un'istanza CacheExpires con un valore corrispondente a Timer che chiama il suo metodo FlushExpiredItems ogni venti secondi.

Questo metodo itera su un'altra raccolta di "bucket" di dati di scadenza della cache (una serie di istanze ExpiresBucket) in serie, chiamando a turno il metodo FlushExpiredItems di ciascun bucket.

Questo metodo (ExpiresBucket.FlushExpiredItems) primi itera tutti gli elementi della cache nel secchio e se un elemento è scaduto, segna scaduto. Quindi (sto molto semplificando qui) itera gli elementi che ha contrassegnato come scaduti e li rimuove, eseguendo il CacheItemRemovedCallback (in realtà, chiama CacheSingle.Remove, che chiama CacheInternal.DoRemove, quindi CacheSingle.UpdateCache, quindi CacheEntry.Close, che in realtà chiama il callback).

Tutto ciò avviene in serie, quindi c'è una possibilità che qualcosa possa bloccare l'intero processo e trattenere le cose (e spingere indietro la scadenza dell'elemento della cache dalla sua scadenza specificata).

Tuttavia, a questa risoluzione temporale, con un intervallo di scadenza minimo di venti secondi, l'unica parte del processo che potrebbe bloccare per un periodo di tempo significativo è l'esecuzione dello CacheItemRemovedCallbacks. Ognuna di queste potrebbe teoricamente bloccare un thread dato da un tempo indefinito. (Anche se venti secondi dopo, il Timer sarebbe generare un'altra FlushExpiredItems thread.)

In sintesi, Asp.Net non si garanzia che eseguirà le richiamate al momento specificato, ma lo farà in alcune condizioni. Fintanto che gli intervalli di scadenza sono distanti più di venti secondi e finché la cache non deve eseguire il dispendio di tempo CacheItemRemovedCallbacks (a livello globale - qualsiasi callback potrebbe interferire con altri), è possibile eseguire callback di scadenza in base alla pianificazione. Ciò sarà abbastanza buono per alcune applicazioni, ma non per gli altri.

+3

Eccellente, grazie per aver scavato in questo. Sono abbastanza sicuro che questo è migliorato da quando l'ho scavato in Reflector diversi anni fa. Inoltre, ASP.NET 4 include ulteriori miglioramenti per la memorizzazione nella cache, alcuni dei quali sono elencati qui: http://www.asp.net/learn/whitepapers/aspnet40/ –

+1

Piacere mio: si è rivelato piuttosto interessante. Certo, ora che l'hai tirato fuori, devo passare una parte del mio week-end a guardare gli ultimi 4.0 beta assemblati, fai colpo! ;) –

5

Gli elementi scaduti non vengono immediatamente rimossi dalla cache, sono solo contrassegnati come scaduti. Non ricevi una richiamata fino a quando manchi una cache. Mi sono imbattuto in questo back in 1.1 giorni ASP.NET, and it hasn't changed.

Ci possono essere casi in cui gli elementi scaduti vengono rimossi immediatamente, ad esempio se c'è poca memoria e CPU alta, ma non si può contare su di esso.

Di solito uso un timer che ricarica periodicamente la cache.

+1

Mi piace la tecnica che sostituisci le scadenze della cache nel tuo articolo! Ma sono ancora scettico: il mio sito di test è stato in esecuzione tutto il giorno, incustodito praticamente senza nient'altro sulla mia macchina, colpendo doverosamente il suo callback ogni minuto. Perché dici che sono contrassegnati solo come scaduti? È a causa dell'articolo di Steve Smith a cui ti colleghi? (http://msdn.microsoft.com/en-us/library/aa478965.aspx) Solo * asserisce * che gli elementi della cache scaduti non vengono rimossi - e ... –

+0

... non è chiaro se sta parlando su particolari scadenze della cache o solo su quella che usa (configurazione NoAbsoluteExpiration/TimeSpan.Zero). Per favore lasciatemi aggiungere che non intendo essere irrispettoso nei confronti di Steve (o di te!), Che ha contribuito notevolmente alla comunità .NET in generale. Ciò contraddice ciò che vedo con i miei stessi occhi (e sono certo che i miei test non sono viziati dall'alta memoria/utilizzo della CPU). Credo di aver bisogno di scaricare Reflector e vedere da solo, e che punto aggiornerò volentieri questo e mangerò un po 'di merda. :) –

+0

Mi piacerebbe essere smentito! Non ho visto le richiamate in modo affidabile in .NET 1.1, 2.0 o 3.5. Hai qualcosa che sta facendo il ping al sito mantenendo il sito vivo?Puoi dare più specifiche sul tuo codice e hosting? –

Problemi correlati