2009-09-16 15 views
19

Cuando agrega un artículo al System.Web.Caching.Cache con una fecha de vencimiento absoluta, como en el siguiente ejemplo, ¿cómo se comporta Asp.Net? Lo hace:¿Cuándo elimina Asp.Net los elementos caché caducados?

  1. Simplemente marca el artículo como expirado, a continuación, ejecutar el CacheItemRemovedCallback en el siguiente intento de acceso?

  2. ¿Quitar el elemento del caché y ejecutar el CacheItemRemovedCallback inmediatamente?

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

MSDN parece indicar que sucede inmediatamente. Por ejemplo, the "Expiration" section of the "ASP.NET Caching Overview" dice "ASP.NET elimina automáticamente elementos de la caché cuando caducan". De forma similar, el ejemplo del tema "How to: Notify an Application When an Item Is Removed from the Cache" dice "Si transcurren más de 15 segundos entre llamadas a GetReport [un método en el ejemplo], ASP.NET elimina el informe de la memoria caché".

Aún así, ninguno de estos es inequívoco. No dicen "la devolución de llamada se ejecuta inmediatamente" y podría concebir cómo sus escritores podrían haber pensado que la opción 1 anterior cuenta como 'eliminar' un elemento. Así que hice una prueba rápida y sucia, y he aquí, parece que se está ejecutando de inmediato: recibo devoluciones de llamada regulares de sesenta segundos, incluso cuando nadie está accediendo a mi sitio.

No obstante, mi prueba fue rápida y sucia, y en los comentarios a mi respuesta al Is there a way to run a process every day in a .Net web application without writing a windows service or SQL server jobs, alguien ha sugerido que Asp.Net realmente difiere la eliminación y ejecución de la devolución de llamada hasta que algo intente acceder al caché nuevamente.

¿Alguien puede resolver esto de manera autoritaria o esto simplemente se considera un detalle de implementación?

+2

No creo que pueda haber una respuesta autorizada a esa pregunta porque, como a Raymond Chen le gusta señalar tan a menudo, usted interpreta el comportamiento de una versión de software para ser autorizada para todas las versiones futuras. En mi experiencia, esta es una mala idea ya que ASP.NET podría cambiar su comportamiento en cualquier momento y romper su aplicación. – dkackman

+1

¿por qué no lo prueba? En su retrollamada, escriba en un archivo y vea la fecha de creación y cómo se relaciona con la caducidad. –

+0

@dkackman - No necesito una respuesta "ahora y siempre", estoy dispuesto a conformarme con respuestas autorizadas para .NET 2.0 y 3.5. No parece ser solo un detalle de implementación para mí: esperaría que la documentación dijera en alguna parte que la eliminación real no es determinista si ese fuera el caso. Tal vez MS no está de acuerdo. Solo estoy tratando de ver si acabo de pasar por alto algo en la documentación. –

Respuesta

35

¡Hurra para Reflector!

elementos de caché expirados son en realidad eliminado (y devoluciones de llamada llama) cuando:

1) Algo intenta acceder al elemento de la caché.

2) Se ejecuta el método ExpiresBucket.FlushExpiredItems y se pone al artículo. Este método está codificado para ejecutarse cada 20 segundos (la respuesta aceptada a la pregunta Changing frequency of ASP.NET cache item expiration de StackOverflow corrobora mi lectura de este código a través de Reflector). Sin embargo, esto necesita una calificación adicional (para la cual sigue leyendo).


Asp.Net mantiene una caché para cada CPU en el servidor (no estoy seguro de si éstas representan las CPU lógica o física); cada uno de estos mantiene una instancia CacheExpires que tiene un Timer correspondiente que llama a su método FlushExpiredItems cada veinte segundos.

Este método itera sobre otra colección de 'cubos' de datos de caducidad de caché (una matriz de ExpiresBucket instancias) en serie, llamando el método FlushExpiredItems de cada cubo a su vez.

Este método (ExpiresBucket.FlushExpiredItems) primero repite todos los elementos de la caché en el cubo y si ha caducado un elemento, lo marca expiró. Luego (estoy simplificando enormemente aquí) repite los elementos que ha marcado caducados y los elimina ejecutando CacheItemRemovedCallback (en realidad, llama a CacheSingle.Remove, que llama a CacheInternal.DoRemove, luego a CacheSingle.UpdateCache, luego a CacheEntry.Close, que en realidad llama a la devolución de llamada).

Todo eso sucede en serie, por lo que existe la posibilidad de que algo pueda bloquear todo el proceso y mantener todo (y empujar la caducidad del elemento de caché desde su tiempo de caducidad especificado).

Sin embargo, en esta resolución temporal, con un intervalo de caducidad mínimo de veinte segundos, la única parte del proceso que podría bloquear durante un período de tiempo significativo es la ejecución del CacheItemRemovedCallbacks. Cualquiera de estos podría bloquear un hilo dado TimerFlushExpiredItems indefinidamente. (Aunque veinte segundos más tarde, el Timer generaría otra FlushExpiredItems hilo.)

En resumen, no se Asp.Net garantía de que va a ejecutar las devoluciones de llamada a la hora especificada, pero lo harán bajo algunas condiciones. Siempre que los intervalos de caducidad estén separados por más de veinte segundos, y siempre que la caché no tenga que ejecutar el lento CacheItemRemovedCallbacks (a nivel mundial, cualquier retrollamada podría interferir con otras), puede ejecutar devoluciones de llamadas a la fecha prevista. Eso será lo suficientemente bueno para algunas aplicaciones, pero no será suficiente para otras.

+3

Excelente, gracias por profundizar en esto. Estoy bastante seguro de que esto ha mejorado desde que lo rebusqué en Reflector hace varios años. Además, ASP.NET 4 incluye mejoras adicionales para el almacenamiento en caché, algunas de las cuales se enumeran aquí: http://www.asp.net/learn/whitepapers/aspnet40/ –

+1

Fue un placer, resultó ser bastante interesante. Por supuesto, ahora que lo has sacado a relucir, tengo que pasar parte de mi fin de semana mirando los últimos ensamblados de beta de 4.0. ¡Quema! ;) –

5

Los elementos caducados no se eliminan inmediatamente de la memoria caché, solo se marcan como caducados. No recibes una devolución de llamada hasta que falta un caché. Me encontré con esto en ASP.NET 1.1 días, and it hasn't changed.

Puede haber casos en que los elementos caducados se eliminen inmediatamente, como si hay poca memoria y CPU alta, pero no puede contar con ello.

Normalmente uso un temporizador que recarga la caché de forma regular.

+1

¡Me gusta la técnica que sustituyes las caducidades de caché en tu artículo! Pero todavía soy escéptico: mi sitio de prueba ha estado funcionando todo el día, sin supervisión y prácticamente sin nada más que se ejecute en mi máquina, cumpliendo diligentemente su devolución de llamada cada minuto. ¿Por qué dices que solo están marcados como caducados? ¿Es por el artículo de Steve Smith al que enlazas? (http://msdn.microsoft.com/en-us/library/aa478965.aspx) Solo * afirma * que los elementos caché caducados no se eliminan, y ... –

+0

... no está claro si está hablando sobre expiraciones de caché particulares o solo la que usa (la configuración NoAbsoluteExpiration/TimeSpan.Zero). Por favor, permítanme agregar también que no quiero ser irrespetuoso con Steve (¡o con usted!), Quien ha contribuido poderosamente a la comunidad .NET en general. Sin embargo, contradice lo que veo con mis propios ojos (y estoy seguro de que mis pruebas no están viciadas por el uso de memoria/CPU). Supongo que necesito descargar Reflector y ver por mí mismo, y en qué punto me gustaría actualizar esto y comer un cuervo bien merecido. :) –

+0

¡Me encantaría que se demuestre que estoy equivocado! No he visto que las devoluciones de llamada sucedan de manera confiable en .NET 1.1, 2.0 o 3.5. ¿Tiene algo que está haciendo ping en el sitio manteniendo vivo el sitio?¿Puedes dar más detalles sobre tu código y tu hosting? –

Cuestiones relacionadas