2009-09-16 8 views
19

Lorsque vous ajoutez un élément au System.Web.Caching.Cache avec une date d'expiration absolue, comme dans l'exemple suivant, comment se comporte Asp.Net? Est-ce que cela:Quand Asp.Net supprime-t-il les éléments du cache expirés?

  1. simplement marquer l'élément comme expiré, puis exécutez la CacheItemRemovedCallback sur la prochaine tentative d'accès?

  2. Supprimer l'élément du cache et exécuter le CacheItemRemovedCallback immédiatement?

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

MSDN semble indiquer qu'il se produit immédiatement. Par exemple, the "Expiration" section of the "ASP.NET Caching Overview" indique "ASP.NET supprime automatiquement les éléments du cache lorsqu'ils expirent." De même, l'exemple du sujet "How to: Notify an Application When an Item Is Removed from the Cache" indique "Si plus de 15 secondes s'écoulent entre les appels à GetReport [une méthode dans l'exemple], ASP.NET supprime le rapport du cache."

Pourtant, aucun de ces deux n'est sans ambiguïté. Ils ne disent pas "le rappel est exécuté immédiatement" et je pourrais concevoir comment leurs auteurs auraient pu penser que l'option 1 ci-dessus compte comme "enlever" un article. J'ai donc fait un test rapide et sale, et voilà, il semble être en train de s'exécuter immédiatement - je reçois régulièrement des rappels de soixante-secondes même si personne n'accède à mon site. Néanmoins, mon test a été rapide et sale, et dans les commentaires à ma réponse à Is there a way to run a process every day in a .Net web application without writing a windows service or SQL server jobs, quelqu'un a suggéré qu'Asp.Net reporte effectivement la suppression et l'exécution du rappel jusqu'à ce que quelque chose tente à nouveau d'accéder au cache.

Quelqu'un peut-il régler cette autorité ou est-ce juste considéré comme un détail d'implémentation?

+2

Je ne pense pas qu'il puisse y avoir une réponse faisant autorité à cette question parce que, comme Raymond Chen le fait remarquer si souvent, vous interprétez le comportement d'une version du logiciel comme faisant autorité pour toutes les futures versions. Dans mon expérience c'est une mauvaise idée car ASP.NET pourrait changer son comportement à tout moment et casser votre application. – dkackman

+1

pourquoi ne pas le tester. Sur votre callback, écrivez dans un fichier et voyez la date de création et comment elle se rapporte à l'expiration. –

+0

@dkackman - Je n'ai pas besoin de réponse "maintenant et pour toujours", je suis prêt à me contenter de réponses officielles pour .NET 2.0 et 3.5. Cela ne me semble pas être un simple détail de mise en œuvre: je m'attendrais à ce que la documentation indique quelque part que le retrait effectif n'est pas déterministe si tel était le cas. Peut-être que MS est en désaccord. J'essaie juste de voir si j'ai oublié quelque chose dans la documentation. –

Répondre

35

Hourra pour Reflector!

éléments du cache sont arrivés à expiration effectivement enlevés (et callbacks appelé) lorsque:

1) Quelque chose tente d'accéder à l'élément de cache.

2) La méthode ExpiresBucket.FlushExpiredItems s'exécute et accède à l'élément. Cette méthode est codée en dur pour s'exécuter toutes les 20 secondes (la réponse acceptée à la question StackOverflow Changing frequency of ASP.NET cache item expiration corrobore ma lecture de ce code via Reflector). Cependant, cela a besoin de qualification supplémentaire (pour lequel lire).


Asp.Net maintient un cache pour chaque processeur sur le serveur (je ne sais pas si ceux-ci représentent les processeurs logiques ou physiques); chacun d'eux maintient une instance CacheExpires qui a un Timer correspondant qui appelle sa méthode FlushExpiredItems toutes les vingt secondes.

Cette méthode itère sur une autre collection de 'buckets' de données d'expiration de cache (un tableau de ExpiresBucket instances) en série, appelant la méthode FlushExpiredItems de chaque compartiment à tour de rôle.

Cette méthode (ExpiresBucket.FlushExpiredItems) premier itère affiche tous les éléments du cache dans le seau et si un article est expiré, marque son expiration. Puis (je simplifie énormément ici) il itère les éléments qu'il a marqués expirés et les supprime, exécutant le CacheItemRemovedCallback (en fait, il appelle CacheSingle.Remove, qui appelle CacheInternal.DoRemove, puis CacheSingle.UpdateCache, puis CacheEntry.Close, qui appelle réellement le rappel). Tout cela se produit en série, il est donc possible que quelque chose bloque tout le processus et le retarde (et repousse l'expiration de l'élément de cache à partir de l'heure d'expiration spécifiée).

Cependant, à cette résolution temporelle, avec un intervalle d'expiration minimum de vingt secondes, la seule partie du processus qui pourrait bloquer pendant une durée significative est l'exécution du CacheItemRemovedCallbacks. N'importe lequel d'entre eux pourrait éventuellement bloquer un fil TimerFlushExpiredItems donné indéfiniment. (Bien que vingt secondes plus tard, le Timer engendrerait un autre fil FlushExpiredItems.)

Pour résumer, Asp.Net ne garantie qu'il exécutera callbacks à l'heure indiquée, mais il le fera dans certaines conditions. Tant que les intervalles d'expiration sont éloignés de plus de vingt secondes, et tant que le cache n'a pas besoin de temps CacheItemRemovedCallbacks (globalement - tous les rappels peuvent potentiellement interférer avec d'autres), il peut exécuter des rappels d'expiration dans les délais. Cela sera suffisant pour certaines applications, mais pas pour d'autres.

+3

Excellent, merci de creuser dans ce domaine. Je suis presque certain que cela s'est amélioré depuis que je l'ai découvert dans Reflector il y a plusieurs années. En outre, ASP.NET 4 inclut des améliorations supplémentaires pour la mise en cache, dont certaines sont répertoriées ici: http://www.asp.net/learn/whitepapers/aspnet40/ –

+1

Mon plaisir - il s'est avéré être assez intéressant. Bien sûr, maintenant que vous l'avez soulevé, je dois passer une partie de mon week-end à regarder les dernières assemblées bêta 4.0, vous faire exploser! ;) –

5

Les éléments expirés ne sont pas immédiatement supprimés du cache, ils sont simplement marqués comme ayant expiré. Vous n'obtenez pas de rappel jusqu'à ce qu'un cache soit manqué. J'ai couru dans ce dos dans les jours ASP.NET 1.1, and it hasn't changed.

Il est possible que des éléments expirés soient immédiatement supprimés (par exemple, si la mémoire est faible et le processeur élevé), mais vous ne pouvez pas compter dessus.

J'utilise généralement une minuterie qui recharge régulièrement le cache.

+1

J'aime la technique que vous substituez aux expirations de cache dans votre article! Mais je suis toujours sceptique: mon site de test a fonctionné toute la journée, sans surveillance, avec pratiquement rien d'autre fonctionnant sur ma machine, atteignant consciencieusement son rappel à chaque minute. Pourquoi dites-vous qu'ils sont seulement marqués comme expirés? Est-ce à cause de l'article de Steve Smith auquel vous liez? (http://msdn.microsoft.com/en-us/library/aa478965.aspx) Il * seulement * affirme * que les éléments en cache expirés ne sont pas supprimés - et ... –

+0

... il est un peu difficile de savoir s'il parle à propos d'expirations de cache particulières ou juste celle qu'il utilise (la configuration NoAbsoluteExpiration/TimeSpan.Zero). S'il vous plaît laissez-moi ajouter aussi que je ne veux pas être irrespectueux envers Steve (ou vous!), Qui a contribué puissamment à la communauté .NET dans son ensemble. Il contredit ce que je vois de mes propres yeux (et je suis certain que mes tests ne sont pas viciés par l'utilisation de mémoire élevée/cpu). Je suppose que j'ai besoin de télécharger Reflector et de voir par moi-même, et à quel point je vais le mettre à jour avec plaisir et manger un corbeau bien mérité. :) –

+0

J'aimerais bien avoir tort! Je n'ai pas vu les rappels se produire de manière fiable dans .NET 1.1, 2.0 ou 3.5. Avez-vous quelque chose qui fait un ping sur le site en gardant le site vivant?Pouvez-vous donner plus de détails sur votre code et votre hébergement? –

Questions connexes