Evento
Campionato do Mundo de Power BI DataViz
Feb 14, 4 PM - Mar 31, 4 PM
Con 4 posibilidades de entrar, poderías gañar un paquete de conferencias e facelo ao Live Grand Finale en Las Vegas
Máis informaciónEste explorador xa non é compatible.
Actualice a Microsoft Edge para dispoñer das funcionalidades máis recentes, as actualizacións de seguranza e a asistencia técnica.
Por Rick Anderson, John Luo y Steve Smith
El almacenamiento en caché puede mejorar significativamente el rendimiento y la escalabilidad de una aplicación al reducir el trabajo necesario para generar contenido. El almacenamiento en caché funciona mejor con datos que cambian con poca frecuencia y es caro de generar. El almacenamiento en caché hace una copia de los datos que puede devolverse mucho más rápido que desde la fuente. Las aplicaciones deberían escribirse y probarse para que nunca dependan de datos almacenados en caché.
ASP.NET Core admite varias cachés diferentes. La caché más sencilla se basa en el IMemoryCache. IMemoryCache
representa una caché almacenada en la memoria del servidor web. Las aplicaciones que se ejecutan en una granja de servidores (varios servidores) deben asegurarse de que las sesiones son fijas cuando se utiliza la caché en memoria. Las sesiones fijas garantizan que todas las solicitudes de un cliente se dirijan al mismo servidor. Por ejemplo, las aplicaciones Azure Web utilizan Application Request Routing (ARR) para dirigir todas las solicitudes al mismo servidor.
Las sesiones no fijas en una granja de servidores web requieren una caché distribuida para evitar problemas de consistencia de la caché. Para algunas aplicaciones, una caché distribuida puede admitir una mayor escalabilidad horizontal que una caché en memoria. El uso de una caché distribuida descarga la memoria caché a un proceso externo.
La caché en memoria puede almacenar cualquier objeto. La interfaz de la caché distribuida está limitada a byte[]
. La caché en memoria y la caché distribuida almacenan los elementos de la caché como pares clave-valor.
System.Runtime.Caching/MemoryCache (Paquete NuGet) puede utilizarse con:
Microsoft.Extensions.Caching.Memory/IMemoryCache
(descrito en este artículo) se recomienda sobre System.Runtime.Caching
/MemoryCache
porque está mejor integrado en ASP.NET Core. Por ejemplo, IMemoryCache
funciona de forma nativa con ASP.NET Core inyección de dependencias.
Utilice System.Runtime.Caching
/MemoryCache
como puente de compatibilidad al portar código de ASP.NET 4.x a ASP.NET Core.
Aviso
Utilizar una cache de memoria compartida de Inyección de Dependencia y llamar a SetSize
, Size
, o SizeLimit
para limitar el tamaño de la cache puede causar que la aplicación no funcione. Cuando se establece un límite de tamaño en una caché, todas las entradas deben especificar un tamaño cuando se añaden. Esto puede dar lugar a problemas, ya que los desarrolladores pueden no tener un control total sobre lo que utiliza la caché compartida.
Cuando utilice SetSize
, Size
, o SizeLimit
para limitar la caché, cree un singleton de caché para el almacenamiento en caché. Para más información y un ejemplo, consulte Use SetSize, Size y SizeLimit para limitar el tamaño de la caché.
Una caché compartida es aquella compartida por otros frameworks o librerías.
La caché en memoria es un servicio al que se hace referencia desde una aplicación utilizando inyección de dependencias. Solicita la instancia IMemoryCache
en el constructor:
public class IndexModel : PageModel
{
private readonly IMemoryCache _memoryCache;
public IndexModel(IMemoryCache memoryCache) =>
_memoryCache = memoryCache;
// ...
El siguiente código utiliza TryGetValue para comprobar si una hora está en la caché. Si una hora no está en la caché, se crea una nueva entrada y se añade a la caché con Set:
public void OnGet()
{
CurrentDateTime = DateTime.Now;
if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
cacheValue = CurrentDateTime;
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
_memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
CacheCurrentDateTime = cacheValue;
}
En el código anterior, la entrada de la caché se configura con una caducidad variable de tres segundos. Si no se accede a la entrada de la caché durante más de tres segundos, se expulsa de la caché. Cada vez que se accede a la entrada de la caché, ésta permanece en la caché durante 3 segundos más. La clase CacheKeys
forma parte de la muestra de descarga.
Se muestra la hora actual y la hora en caché:
<ul>
<li>Current Time: @Model.CurrentDateTime</li>
<li>Cached Time: @Model.CacheCurrentDateTime</li>
</ul>
El siguiente código utiliza el método de extensión Set
para almacenar en caché datos durante un tiempo relativo sin MemoryCacheEntryOptions
:
_memoryCache.Set(CacheKeys.Entry, DateTime.Now, TimeSpan.FromDays(1));
En el código anterior, la entrada de caché se configura con una caducidad relativa de un día. La entrada de caché se expulsa de la memoria caché después de un día, incluso si se accede a ella dentro de este período de tiempo de espera.
El siguiente código utiliza GetOrCreate y GetOrCreateAsync para almacenar datos en caché.
public void OnGetCacheGetOrCreate()
{
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});
// ...
}
public async Task OnGetCacheGetOrCreateAsync()
{
var cachedValue = await _memoryCache.GetOrCreateAsync(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
// ...
}
El siguiente código llama a Get para obtener la hora en caché:
var cacheEntry = _memoryCache.Get<DateTime?>(CacheKeys.Entry);
El siguiente código obtiene o crea un elemento en caché con caducidad absoluta:
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
Un elemento en caché con una caducidad variable corre el riesgo de no caducar nunca. Si se accede repetidamente al elemento en caché dentro del intervalo de caducidad variable, el elemento nunca caduca. Combina una caducidad variable con una absoluta para garantizar que el elemento caduca. La caducidad absoluta establece un límite superior sobre el tiempo que el elemento puede estar en caché, al tiempo que permite que el elemento caduque antes si no se solicita dentro del intervalo de caducidad variable. Si el intervalo de caducidad o el tiempo de caducidad absoluta pasan, el elemento se expulsa de la caché.
El siguiente código obtiene o crea un elemento de la caché con un intervalo de caducidad y absoluto:
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.CallbackEntry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
El código anterior garantiza que los datos no se almacenarán en caché durante más tiempo que el tiempo absoluto.
GetOrCreate, GetOrCreateAsync y Get son métodos de extensión de la clase CacheExtensions. Estos métodos amplían la capacidad de IMemoryCache.
En el ejemplo siguiente:
public void OnGetCacheRegisterPostEvictionCallback()
{
var memoryCacheEntryOptions = new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.NeverRemove)
.RegisterPostEvictionCallback(PostEvictionCallback, _memoryCache);
_memoryCache.Set(CacheKeys.CallbackEntry, DateTime.Now, memoryCacheEntryOptions);
}
private static void PostEvictionCallback(
object cacheKey, object cacheValue, EvictionReason evictionReason, object state)
{
var memoryCache = (IMemoryCache)state;
memoryCache.Set(
CacheKeys.CallbackMessage,
$"Entry {cacheKey} was evicted: {evictionReason}.");
}
Una instancia MemoryCache
puede especificar y aplicar opcionalmente un límite de tamaño. El límite de tamaño de la caché no tiene una unidad de medida definida porque la caché no tiene un mecanismo para medir el tamaño de las entradas. Si se establece el límite de tamaño de la caché, todas las entradas deben especificar el tamaño. El tiempo de ejecución de ASP.NET Core no limita el tamaño de la caché en función de la presión de la memoria. Depende del desarrollador limitar el tamaño de la caché. El tamaño especificado está en unidades que el desarrollador elige.
Por ejemplo:
Si SizeLimit no se establece, la caché crece sin límite. El tiempo de ejecución de ASP.NET Core no recorta la caché cuando la memoria del sistema es baja. Las aplicaciones deben diseñarse para:
El siguiente código crea un MemoryCache de tamaño fijo sin unidades accesible por inyección de dependencia:
public class MyMemoryCache
{
public MemoryCache Cache { get; } = new MemoryCache(
new MemoryCacheOptions
{
SizeLimit = 1024
});
}
SizeLimit
no tiene unidades. Las entradas de caché deben especificar el tamaño en las unidades que consideren más apropiadas si se ha establecido el límite de tamaño de caché. Todos los usuarios de una instancia de caché deben utilizar el mismo sistema de unidades. Una entrada no se almacenará en caché si la suma de los tamaños de las entradas almacenadas en caché supera el valor especificado por SizeLimit
. Si no se establece ningún límite de tamaño de caché, se ignora el tamaño de caché establecido en la entrada.
El siguiente código registra MyMemoryCache
con el contenedor de inyección de dependencia:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<MyMemoryCache>();
MyMemoryCache
se crea como una caché de memoria independiente para los componentes que son conscientes de esta caché de tamaño limitado y saben cómo establecer el tamaño de la entrada de caché adecuadamente.
El tamaño de la entrada de la caché puede establecerse mediante el método de extensión SetSize o la propiedad Size:
if (!_myMemoryCache.Cache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSize(1);
// cacheEntryOptions.Size = 1;
_myMemoryCache.Cache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
En el código anterior, las dos líneas resaltadas consiguen el mismo resultado al establecer el tamaño de la entrada de la caché. SetSize
se proporciona por conveniencia cuando se encadenan llamadas a new MemoryCacheOptions()
.
MemoryCache.Compact
intenta eliminar el porcentaje especificado de la caché en el siguiente orden:
Los elementos anclados con prioridad NeverRemove no se eliminan nunca. El siguiente código elimina un elemento de la caché y llama a Compact
para eliminar el 25% de las entradas de la caché:
_myMemoryCache.Cache.Remove(CacheKeys.Entry);
_myMemoryCache.Cache.Compact(.25);
Para más información, consulte el código fuente de Compact en GitHub.
El siguiente ejemplo muestra cómo caducar una entrada de la caché si caduca una entrada dependiente. Se añade un CancellationChangeToken al elemento en caché. Cuando se llama a Cancel
sobre CancellationTokenSource
, ambas entradas de la caché son desalojadas:
public void OnGetCacheCreateDependent()
{
var cancellationTokenSource = new CancellationTokenSource();
_memoryCache.Set(
CacheKeys.DependentCancellationTokenSource,
cancellationTokenSource);
using var parentCacheEntry = _memoryCache.CreateEntry(CacheKeys.Parent);
parentCacheEntry.Value = DateTime.Now;
_memoryCache.Set(
CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cancellationTokenSource.Token));
}
public void OnGetCacheRemoveDependent()
{
var cancellationTokenSource = _memoryCache.Get<CancellationTokenSource>(
CacheKeys.DependentCancellationTokenSource);
cancellationTokenSource.Cancel();
}
El uso de un CancellationTokenSource permite desalojar varias entradas de la caché en grupo. Con el patrón using
en el código anterior, las entradas de caché creadas dentro del ámbito using
heredan los disparadores y la configuración de caducidad.
La caducidad no se produce en segundo plano. No hay ningún temporizador que escanee activamente la caché en busca de elementos caducados. Cualquier actividad en la caché (Get
, Set
, Remove
) puede desencadenar una búsqueda en segundo plano de elementos caducados. Un temporizador en CancellationTokenSource
(CancelAfter) también elimina la entrada y activa una búsqueda de elementos caducados. El siguiente ejemplo utiliza CancellationTokenSource(TimeSpan) para el token registrado. Cuando este token se activa, elimina la entrada inmediatamente y activa las devoluciones de llamada de desalojo:
if (!_memoryCache.TryGetValue(CacheKeys.Entry, out DateTime cacheValue))
{
cacheValue = DateTime.Now;
var cancellationTokenSource = new CancellationTokenSource(
TimeSpan.FromSeconds(10));
var cacheEntryOptions = new MemoryCacheEntryOptions()
.AddExpirationToken(
new CancellationChangeToken(cancellationTokenSource.Token))
.RegisterPostEvictionCallback((key, value, reason, state) =>
{
((CancellationTokenSource)state).Dispose();
}, cancellationTokenSource);
_memoryCache.Set(CacheKeys.Entry, cacheValue, cacheEntryOptions);
}
Cuando se utiliza una devolución de llamada para repoblar un elemento en caché:
Cuando una entrada de la caché se utiliza para crear otra, la entrada hija copia los tokens de caducidad y los ajustes de caducidad basados en el tiempo de la entrada primaria. El elemento secundario no caduca por la eliminación o actualización manual de la entrada primaria.
Utilice PostEvictionCallbacks para establecer las devoluciones de llamada que se activarán después de que la entrada de la caché sea desalojada de la caché.
Para la mayoría de las aplicaciones, IMemoryCache
está activado. Por ejemplo, llamar a AddMvc
, AddControllersWithViews
, AddRazorPages
, AddMvcCore().AddRazorViewEngine
, y muchos otros métodos Add{Service}
en Program.cs
, habilita IMemoryCache
. Para aplicaciones que no llamen a uno de los métodos Add{Service}
anteriores, puede ser necesario llamar a AddMemoryCache en Program.cs
.
Utiliza un servicio en segundo plano como IHostedService para actualizar la caché. El servicio en segundo plano puede volver a calcular las entradas y luego asignarlas a la caché solo cuando estén listas.
Vea o descargue el código de ejemplo (cómo descargarlo)
El almacenamiento en caché puede mejorar significativamente el rendimiento y la escalabilidad de una aplicación al reducir el trabajo necesario para generar contenido. El almacenamiento en caché funciona mejor con datos que cambian con poca frecuencia y es caro de generar. El almacenamiento en caché hace una copia de los datos que puede devolverse mucho más rápido que desde la fuente. Las aplicaciones deberían escribirse y probarse para que nunca dependan de datos almacenados en caché.
ASP.NET Core admite varias cachés diferentes. La caché más sencilla se basa en el IMemoryCache. IMemoryCache
representa una caché almacenada en la memoria del servidor web. Las aplicaciones que se ejecutan en una granja de servidores (varios servidores) deben asegurarse de que las sesiones son fijas cuando se utiliza la caché en memoria. Las sesiones fijas garantizan que todas las solicitudes posteriores de un cliente se dirijan al mismo servidor. Por ejemplo, las aplicaciones web de Azure utilizan Application Request Routing (ARR) para dirigir todas las solicitudes posteriores al mismo servidor.
Las sesiones no fijas en una granja de servidores web requieren una caché distribuida para evitar problemas de consistencia de la caché. Para algunas aplicaciones, una caché distribuida puede admitir una mayor escalabilidad horizontal que una caché en memoria. El uso de una caché distribuida descarga la memoria caché a un proceso externo.
La caché en memoria puede almacenar cualquier objeto. La interfaz de la caché distribuida está limitada a byte[]
. La caché en memoria y la caché distribuida almacenan los elementos de la caché como pares clave-valor.
System.Runtime.Caching/MemoryCache (Paquete NuGet) puede utilizarse con:
Microsoft.Extensions.Caching.Memory/IMemoryCache
(descrito en este artículo) se recomienda sobre System.Runtime.Caching
/MemoryCache
porque está mejor integrado en ASP.NET Core. Por ejemplo, IMemoryCache
funciona de forma nativa con ASP.NET Core inyección de dependencias.
Utilice System.Runtime.Caching
/MemoryCache
como puente de compatibilidad al portar código de ASP.NET 4.x a ASP.NET Core.
Aviso
Utilizar una cache de memoria compartida de Inyección de Dependencia y llamar a SetSize
, Size
, o SizeLimit
para limitar el tamaño de la cache puede causar que la aplicación no funcione. Cuando se establece un límite de tamaño en una caché, todas las entradas deben especificar un tamaño cuando se añaden. Esto puede dar lugar a problemas, ya que los desarrolladores pueden no tener un control total sobre lo que utiliza la caché compartida.
Cuando utilice SetSize
, Size
, o SizeLimit
para limitar la caché, cree un singleton de caché para el almacenamiento en caché. Para más información y un ejemplo, consulte Use SetSize, Size y SizeLimit para limitar el tamaño de la caché.
Una caché compartida es aquella compartida por otros frameworks o librerías.
La caché en memoria es un servicio al que se hace referencia desde una aplicación utilizando inyección de dependencias. Solicita la instancia IMemoryCache
en el constructor:
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
El siguiente código utiliza TryGetValue para comprobar si una hora está en la caché. Si una hora no se almacena en caché, se crea una nueva entrada y se añade a la caché con Set. La clase CacheKeys
forma parte de la muestra de descarga.
public static class CacheKeys
{
public static string Entry => "_Entry";
public static string CallbackEntry => "_Callback";
public static string CallbackMessage => "_CallbackMessage";
public static string Parent => "_Parent";
public static string Child => "_Child";
public static string DependentMessage => "_DependentMessage";
public static string DependentCTS => "_DependentCTS";
public static string Ticks => "_Ticks";
public static string CancelMsg => "_CancelMsg";
public static string CancelTokenSource => "_CancelTokenSource";
}
public IActionResult CacheTryGetValueSet()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Save data in cache.
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
}
return View("Cache", cacheEntry);
}
Se muestra la hora actual y la hora en caché:
@model DateTime?
<div>
<h2>Actions</h2>
<ul>
<li><a asp-controller="Home" asp-action="CacheTryGetValueSet">TryGetValue and Set</a></li>
<li><a asp-controller="Home" asp-action="CacheGet">Get</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreate">GetOrCreate</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAsynchronous">CacheGetOrCreateAsynchronous</a></li>
<li><a asp-controller="Home" asp-action="CacheRemove">Remove</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAbs">CacheGetOrCreateAbs</a></li>
<li><a asp-controller="Home" asp-action="CacheGetOrCreateAbsSliding">CacheGetOrCreateAbsSliding</a></li>
</ul>
</div>
<h3>Current Time: @DateTime.Now.TimeOfDay.ToString()</h3>
<h3>Cached Time: @(Model == null ? "No cached entry found" : Model.Value.TimeOfDay.ToString())</h3>
El siguiente código utiliza el método de extensión Set
para almacenar en caché los datos de una hora relativa sin crear el objeto MemoryCacheEntryOptions
:
public IActionResult SetCacheRelativeExpiration()
{
DateTime cacheEntry;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now;
// Save data in cache and set the relative expiration time to one day
_cache.Set(CacheKeys.Entry, cacheEntry, TimeSpan.FromDays(1));
}
return View("Cache", cacheEntry);
}
El valor DateTime
almacenado en caché permanece en la caché mientras haya peticiones dentro del periodo de tiempo de espera.
El siguiente código utiliza GetOrCreate y GetOrCreateAsync para almacenar datos en caché.
public IActionResult CacheGetOrCreate()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
public async Task<IActionResult> CacheGetOrCreateAsynchronous()
{
var cacheEntry = await
_cache.GetOrCreateAsync(CacheKeys.Entry, entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
return View("Cache", cacheEntry);
}
El siguiente código llama a Get para obtener la hora en caché:
public IActionResult CacheGet()
{
var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry);
return View("Cache", cacheEntry);
}
El siguiente código obtiene o crea un elemento en caché con caducidad absoluta:
public IActionResult CacheGetOrCreateAbs()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
Un elemento en caché con una caducidad variable corre el riesgo de no caducar nunca. Si se accede repetidamente al elemento en caché dentro del intervalo de caducidad variable, el elemento nunca caduca. Combina una caducidad variable con una absoluta para garantizar que el elemento caduca. La caducidad absoluta establece un límite superior sobre el tiempo que el elemento puede estar en caché, al tiempo que permite que el elemento caduque antes si no se solicita dentro del intervalo de caducidad variable. Si el intervalo de caducidad o el tiempo de caducidad absoluta pasan, el elemento se expulsa de la caché.
El siguiente código obtiene o crea un elemento de la caché con un intervalo de caducidad y absoluto:
public IActionResult CacheGetOrCreateAbsSliding()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.SetSlidingExpiration(TimeSpan.FromSeconds(3));
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
El código anterior garantiza que los datos no se almacenarán en caché durante más tiempo que el tiempo absoluto.
GetOrCreate, GetOrCreateAsync y Get son métodos de extensión de la clase CacheExtensions. Estos métodos amplían la capacidad de IMemoryCache.
La siguiente muestra:
public IActionResult CreateCallbackEntry()
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Pin to cache.
.SetPriority(CacheItemPriority.NeverRemove)
// Add eviction callback
.RegisterPostEvictionCallback(callback: EvictionCallback, state: this);
_cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions);
return RedirectToAction("GetCallbackEntry");
}
public IActionResult GetCallbackEntry()
{
return View("Callback", new CallbackViewModel
{
CachedTime = _cache.Get<DateTime?>(CacheKeys.CallbackEntry),
Message = _cache.Get<string>(CacheKeys.CallbackMessage)
});
}
public IActionResult RemoveCallbackEntry()
{
_cache.Remove(CacheKeys.CallbackEntry);
return RedirectToAction("GetCallbackEntry");
}
private static void EvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.CallbackMessage, message);
}
Una instancia MemoryCache
puede especificar y aplicar opcionalmente un límite de tamaño. El límite de tamaño de la caché no tiene una unidad de medida definida porque la caché no tiene un mecanismo para medir el tamaño de las entradas. Si se establece el límite de tamaño de la caché, todas las entradas deben especificar el tamaño. El tiempo de ejecución de ASP.NET Core no limita el tamaño de la caché en función de la presión de la memoria. Depende del desarrollador limitar el tamaño de la caché. El tamaño especificado está en unidades que el desarrollador elige.
Por ejemplo:
Si SizeLimit no se establece, la caché crece sin límite. El tiempo de ejecución de ASP.NET Core no recorta la caché cuando la memoria del sistema es baja. Las aplicaciones deben diseñarse para:
El siguiente código crea un MemoryCache de tamaño fijo sin unidades accesible por inyección de dependencia:
// using Microsoft.Extensions.Caching.Memory;
public class MyMemoryCache
{
public MemoryCache Cache { get; private set; }
public MyMemoryCache()
{
Cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 1024
});
}
}
SizeLimit
no tiene unidades. Las entradas de la caché deben especificar el tamaño en las unidades que consideren más apropiadas si se ha establecido el límite de tamaño de la caché. Todos los usuarios de una instancia de caché deben utilizar el mismo sistema de unidades. Una entrada no se almacenará en caché si la suma de los tamaños de las entradas almacenadas en caché supera el valor especificado por SizeLimit
. Si no se ha establecido un límite de tamaño de caché, se ignorará el tamaño de caché establecido en la entrada.
El siguiente código registra MyMemoryCache
con el contenedor de inyección de dependencia.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSingleton<MyMemoryCache>();
}
MyMemoryCache
se crea como una caché de memoria independiente para los componentes que son conscientes de esta caché de tamaño limitado y saben cómo establecer el tamaño de la entrada de caché adecuadamente.
El código siguiente usa MyMemoryCache
:
public class SetSize : PageModel
{
private MemoryCache _cache;
public static readonly string MyKey = "_MyKey";
public SetSize(MyMemoryCache memoryCache)
{
_cache = memoryCache.Cache;
}
[TempData]
public string DateTime_Now { get; set; }
public IActionResult OnGet()
{
if (!_cache.TryGetValue(MyKey, out string cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now.TimeOfDay.ToString();
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Set cache entry size by extension method.
.SetSize(1)
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Set cache entry size via property.
// cacheEntryOptions.Size = 1;
// Save data in cache.
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
}
DateTime_Now = cacheEntry;
return RedirectToPage("./Index");
}
}
El tamaño de la entrada de caché puede establecerse mediante Size o los métodos de extensión SetSize:
public IActionResult OnGet()
{
if (!_cache.TryGetValue(MyKey, out string cacheEntry))
{
// Key not in cache, so get data.
cacheEntry = DateTime.Now.TimeOfDay.ToString();
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Set cache entry size by extension method.
.SetSize(1)
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
// Set cache entry size via property.
// cacheEntryOptions.Size = 1;
// Save data in cache.
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
}
DateTime_Now = cacheEntry;
return RedirectToPage("./Index");
}
MemoryCache.Compact
intenta eliminar el porcentaje especificado de la caché en el siguiente orden:
Los elementos anclados con prioridad NeverRemove nunca se eliminan. El siguiente código elimina un elemento de la caché y llama a Compact
:
_cache.Remove(MyKey);
// Remove 33% of cached items.
_cache.Compact(.33);
cache_size = _cache.Count;
Para más información, consulta el código fuente de Compact en GitHub.
El siguiente ejemplo muestra cómo caducar una entrada de la caché si caduca una entrada dependiente. Se añade un CancellationChangeToken al elemento en caché. Cuando se llama a Cancel
sobre CancellationTokenSource
, ambas entradas de la caché son desalojadas.
public IActionResult CreateDependentEntries()
{
var cts = new CancellationTokenSource();
_cache.Set(CacheKeys.DependentCTS, cts);
using (var entry = _cache.CreateEntry(CacheKeys.Parent))
{
// expire this entry if the dependant entry expires.
entry.Value = DateTime.Now;
entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);
_cache.Set(CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cts.Token));
}
return RedirectToAction("GetDependentEntries");
}
public IActionResult GetDependentEntries()
{
return View("Dependent", new DependentViewModel
{
ParentCachedTime = _cache.Get<DateTime?>(CacheKeys.Parent),
ChildCachedTime = _cache.Get<DateTime?>(CacheKeys.Child),
Message = _cache.Get<string>(CacheKeys.DependentMessage)
});
}
public IActionResult RemoveChildEntry()
{
_cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();
return RedirectToAction("GetDependentEntries");
}
private static void DependentEvictionCallback(object key, object value,
EvictionReason reason, object state)
{
var message = $"Parent entry was evicted. Reason: {reason}.";
((HomeController)state)._cache.Set(CacheKeys.DependentMessage, message);
}
El uso de un CancellationTokenSource permite desalojar varias entradas de la caché en grupo. Con el patrón using
en el código anterior, las entradas de caché creadas dentro del bloque using
heredarán los desencadenadores y la configuración de expiración.
La caducidad no se produce en segundo plano. No hay ningún temporizador que escanee activamente la caché en busca de elementos caducados. Cualquier actividad en la caché (Get
, Set
, Remove
) puede desencadenar una búsqueda en segundo plano de elementos caducados. Un temporizador en CancellationTokenSource
(CancelAfter) también elimina la entrada y activa una búsqueda de elementos caducados. El siguiente ejemplo utiliza CancellationTokenSource(TimeSpan) para el token registrado. Cuando este token se activa, elimina la entrada inmediatamente y activa las devoluciones de llamada de desalojo:
public IActionResult CacheAutoExpiringTryGetValueSet()
{
DateTime cacheEntry;
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
{
cacheEntry = DateTime.Now;
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var cacheEntryOptions = new MemoryCacheEntryOptions()
.AddExpirationToken(new CancellationChangeToken(cts.Token));
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
}
return View("Cache", cacheEntry);
}
Cuando se utiliza una devolución de llamada para repoblar un elemento en caché:
Cuando una entrada de la caché se utiliza para crear otra, la entrada hija copia los tokens de caducidad y los ajustes de caducidad basados en el tiempo de la entrada primaria. El elemento secundario no caduca por la eliminación o actualización manual de la entrada primaria.
Utilice PostEvictionCallbacks para establecer las devoluciones de llamada que se activarán después de que la entrada de la caché sea desalojada de la caché. En el código de ejemplo, CancellationTokenSource.Dispose() se llama a para liberar los recursos no administrados usados por CancellationTokenSource
. Sin embargo, CancellationTokenSource
no se elimina inmediatamente porque la entrada de caché todavía la usa. CancellationToken
se pasa a MemoryCacheEntryOptions
para crear una entrada de caché que expira después de un tiempo determinado. Por lo tanto Dispose
, no se debe llamar a hasta que se quite o expire la entrada de caché. El código de ejemplo llama al RegisterPostEvictionCallback método para registrar una devolución de llamada que se invocará cuando se expulsa la entrada de caché y elimina en CancellationTokenSource
esa devolución de llamada.
Para la mayoría de las aplicaciones, IMemoryCache
está activado. Por ejemplo, llamar a AddMvc
, AddControllersWithViews
, AddRazorPages
, AddMvcCore().AddRazorViewEngine
, y muchos otros métodos Add{Service}
en ConfigureServices
, habilita IMemoryCache
. Para aplicaciones que no llamen a uno de los métodos Add{Service}
anteriores, puede ser necesario llamar a AddMemoryCache en ConfigureServices
.
Utiliza un servicio en segundo plano como IHostedService para actualizar la caché. El servicio en segundo plano puede volver a calcular las entradas y luego asignarlas a la caché solo cuando estén listas.
Comentarios de ASP.NET Core
ASP.NET Core é un proxecto de código aberto. Selecciona unha ligazón para ofrecer comentarios:
Evento
Campionato do Mundo de Power BI DataViz
Feb 14, 4 PM - Mar 31, 4 PM
Con 4 posibilidades de entrar, poderías gañar un paquete de conferencias e facelo ao Live Grand Finale en Las Vegas
Máis información