Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Autorzy: Rick Anderson, John Luo i Steve Smith
Buforowanie może znacznie poprawić wydajność i skalowalność aplikacji, zmniejszając ilość pracy wymaganą do wygenerowania zawartości. Buforowanie działa najlepiej w przypadku danych, które zmieniają się rzadko, a ich generowanie jest kosztowne. Buforowanie tworzy kopię danych, która może zostać zwrócona znacznie szybciej niż ze źródła. Aplikacje powinny być pisane i testowane tak, aby nigdy nie były zależne od danych w pamięci podręcznej.
ASP.NET Core obsługuje kilka różnych pamięci podręcznych. Najprostsza pamięć podręczna oparta jest na IMemoryCache.
IMemoryCache reprezentuje pamięć podręczną przechowywaną w pamięci serwera WWW. Aplikacje działające w farmie serwerów (wielu serwerach) powinny zapewnić, że sesje są trwałe podczas korzystania z pamięci podręcznej w pamięci. Sesje trwałe zapewniają, że wszystkie żądania od klienta trafiają do tego samego serwera. Na przykład aplikacje internetowe platformy Azure używają routingu żądań aplikacji (ARR) do kierowania wszystkich żądań do tego samego serwera.
Sesje nietrwałe w farmie sieci Web wymagają rozproszonej pamięci podręcznej , aby uniknąć problemów ze spójnością pamięci podręcznej. W przypadku niektórych aplikacji rozproszona pamięć podręczna może obsługiwać większe skalowanie w poziomie niż pamięć podręczna w pamięci. Użycie rozproszonej pamięci podręcznej powoduje odciążenie pamięci podręcznej do procesu zewnętrznego.
W pamięci podręcznej w pamięci można przechowywać dowolny obiekt. Interfejs rozproszonej pamięci podręcznej jest ograniczony do byte[]. Pamięć podręczna w pamięci i rozproszona pamięć podręczna przechowują elementy pamięci podręcznej jako pary klucz-wartość.
System.Runtime.Caching/MemoryCache
System.Runtime.Caching / MemoryCache (pakiet NuGet) może być używany z:
- .NET Standard 2.0 lub nowszy.
- Dowolna implementacja platformy .NET przeznaczona dla platformy .NET Standard 2.0 lub nowszej. Na przykład ASP.NET Core 3.1 lub nowszy.
- .NET Framework 4.5 lub nowszy.
Microsoft.Extensions.Caching.Memory/IMemoryCache (opisany w tym artykule) jest zalecany System.Runtime.Caching/MemoryCache , ponieważ jest lepiej zintegrowany z ASP.NET Core. Na przykład IMemoryCache działa natywnie z wstrzykiwaniem zależności ASP.NET Core.
Służy System.Runtime.Caching/MemoryCache jako mostek zgodności podczas przenoszenia kodu z ASP.NET 4.x do ASP.NET Core.
Wskazówki dotyczące pamięci podręcznej
- Kod powinien zawsze mieć opcję awaryjną do pobierania danych i nie zależeć od dostępności wartości w pamięci podręcznej.
- Pamięć podręczna korzysta z rzadkiego zasobu, pamięci. Ogranicz wzrost pamięci podręcznej:
- Nie wkładaj zewnętrznego wejścia do pamięci podręcznej. Na przykład używanie dowolnych danych wejściowych dostarczonych przez użytkownika jako klucza pamięci podręcznej nie jest zalecane, ponieważ dane wejściowe mogą zużywać nieprzewidywalną ilość pamięci.
- Użyj wygaśnięcia, aby ograniczyć wzrost pamięci podręcznej.
- Użyj wartości SetSize, Size i SizeLimit, aby ograniczyć rozmiar pamięci podręcznej. Środowisko uruchomieniowe ASP.NET Core nie ogranicza rozmiaru pamięci podręcznej na podstawie wykorzystania pamięci. To od programisty zależy, czy ograniczy rozmiar pamięci podręcznej.
Korzystanie z usługi IMemoryCache
Warning
Użycie pamięci podręcznej pamięci współużytkowanej z iniekcji zależności i wywołanie SetSize, Sizelub SizeLimit w celu ograniczenia rozmiaru pamięci podręcznej może spowodować awarię aplikacji. Gdy w pamięci podręcznej jest ustawiony limit rozmiaru, wszystkie wpisy muszą określać rozmiar podczas dodawania. Może to prowadzić do problemów, ponieważ programiści mogą nie mieć pełnej kontroli nad tym, co korzysta z udostępnionej pamięci podręcznej.
W przypadku korzystania z SetSize, Sizelub SizeLimit w celu ograniczenia pamięci podręcznej utwórz pojedynczą pamięć podręczną do buforowania. Aby uzyskać więcej informacji i zapoznać się z przykładem, zobacz Używanie wartości SetSize, Size i SizeLimit w celu ograniczenia rozmiaru pamięci podręcznej.
Udostępniona pamięć podręczna to pamięć podręczna współużytkowana przez inne struktury lub biblioteki.
Buforowanie w pamięci to usługa , do której odwołuje się aplikacja przy użyciu wstrzykiwania zależności. Zażądaj instancji IMemoryCache w konstruktorze:
public class IndexModel : PageModel
{
private readonly IMemoryCache _memoryCache;
public IndexModel(IMemoryCache memoryCache) =>
_memoryCache = memoryCache;
// ...
Poniższy kod służy TryGetValue do sprawdzania, czy czas znajduje się w pamięci podręcznej. Jeśli czas nie jest buforowany, tworzony jest nowy wpis i dodawany do pamięci podręcznej za pomocą 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;
}
W poprzednim kodzie wpis pamięci podręcznej jest skonfigurowany z przesuwanym wygaśnięciem wynoszącym trzy sekundy. Jeśli wpis pamięci podręcznej nie jest dostępny przez ponad trzy sekundy, zostanie on usunięty z pamięci podręcznej. Za każdym razem, gdy uzyskuje się dostęp do wpisu w pamięci podręcznej, pozostaje on w pamięci podręcznej przez kolejne 3 sekundy. Klasa CacheKeys jest częścią przykładu pobierania.
Wyświetlany jest bieżący czas i czas zapisany w pamięci podręcznej:
<ul>
<li>Current Time: @Model.CurrentDateTime</li>
<li>Cached Time: @Model.CacheCurrentDateTime</li>
</ul>
Poniższy kod używa Set metody extension do buforowania danych przez czas względny bez MemoryCacheEntryOptions:
_memoryCache.Set(CacheKeys.Entry, DateTime.Now, TimeSpan.FromDays(1));
W poprzednim kodzie wpis pamięci podręcznej jest skonfigurowany ze względnym wygaśnięciem jednego dnia. Wpis pamięci podręcznej zostanie usunięty z pamięci podręcznej po jednym dniu, nawet jeśli dostęp do niego zostanie uzyskany w tym okresie limitu czasu.
Poniższy kod używa GetOrCreate and GetOrCreateAsync do buforowania danych.
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);
});
// ...
}
Następujące wywołania Get kodu w celu pobrania czasu w pamięci podręcznej:
var cacheEntry = _memoryCache.Get<DateTime?>(CacheKeys.Entry);
Poniższy kod pobiera lub tworzy element w pamięci podręcznej z bezwzględnym wygaśnięciem:
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.Entry,
cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
Istnieje ryzyko, że zestaw elementów w pamięci podręcznej z przesuwanym wygaśnięciem nigdy nie wygaśnie. Jeśli element w pamięci podręcznej jest wielokrotnie otwierany w przesuwnym interwale wygasania, element nigdy nie wygasa. Połącz przesuwne wygaśnięcie z bezwzględnym wygaśnięciem, aby zagwarantować, że przedmiot wygaśnie. Bezwzględne wygaśnięcie określa górną granicę tego, jak długo element może być buforowany, jednocześnie umożliwiając wcześniejsze wygaśnięcie elementu, jeśli nie zostanie zażądany w przesuwnym interwale wygaśnięcia. Jeśli minie przesuwny interwał wygaśnięcia lub bezwzględny czas wygaśnięcia, element zostanie usunięty z pamięci podręcznej.
Poniższy kod pobiera lub tworzy element w pamięci podręcznej z wygaśnięciem przesuwnym i bezwzględnym:
var cachedValue = _memoryCache.GetOrCreate(
CacheKeys.CallbackEntry,
cacheEntry =>
{
cacheEntry.SlidingExpiration = TimeSpan.FromSeconds(3);
cacheEntry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20);
return DateTime.Now;
});
Powyższy kod gwarantuje, że dane nie będą buforowane dłużej niż czas bezwzględny.
GetOrCreate, GetOrCreateAsync, i Get są metodami rozszerzenia w CacheExtensions klasie. Metody te rozszerzają IMemoryCachemożliwości programu .
MemoryCacheEntryOptions
Poniższy przykład:
- Ustawia priorytet pamięci podręcznej na CacheItemPriority.NeverRemove.
- Ustawia element, który jest wywoływany PostEvictionDelegate po wykluczeniu wpisu z pamięci podręcznej. Wywołanie zwrotne jest uruchamiane w innym wątku niż kod, który usuwa element z pamięci podręcznej.
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}.");
}
Użyj SetSize, Size i SizeLimit, aby ograniczyć rozmiar pamięci podręcznej
Instancja MemoryCache może opcjonalnie określać i wymuszać limit rozmiaru. Limit rozmiaru pamięci podręcznej nie ma zdefiniowanej jednostki miary, ponieważ pamięć podręczna nie ma mechanizmu mierzenia rozmiaru wpisów. Jeśli ustawiony jest limit rozmiaru pamięci podręcznej, wszystkie wpisy muszą określać rozmiar. Środowisko uruchomieniowe ASP.NET Core nie ogranicza rozmiaru pamięci podręcznej na podstawie wykorzystania pamięci. To od programisty zależy, czy ograniczy rozmiar pamięci podręcznej. Określony rozmiar jest w jednostkach wybranych przez programistę.
Przykład:
- Jeśli aplikacja internetowa głównie buforowała ciągi, każdy rozmiar wpisu pamięci podręcznej może być długością ciągu.
- Aplikacja może określić rozmiar wszystkich wpisów jako 1, a limit rozmiaru to liczba wpisów.
Jeśli SizeLimit nie jest ustawiona, pamięć podręczna rośnie bez ograniczeń. Środowisko uruchomieniowe ASP.NET Core nie przycina pamięci podręcznej, gdy pamięć systemowa jest niska. Aplikacje muszą być zaprojektowane tak, aby:
- Ogranicz wzrost pamięci podręcznej.
- Zadzwoń Compact lub Remove gdy dostępna pamięć jest ograniczona.
Poniższy kod tworzy stały rozmiar MemoryCache bez jednostek dostępny przez wstrzyknięcie zależności:
public class MyMemoryCache
{
public MemoryCache Cache { get; } = new MemoryCache(
new MemoryCacheOptions
{
SizeLimit = 1024
});
}
SizeLimit nie ma jednostek. Wpisy w pamięci podręcznej muszą określać rozmiar w jednostkach, które uznają za najbardziej odpowiednie, jeśli ustawiono limit rozmiaru pamięci podręcznej. Wszyscy użytkownicy instancji pamięci podręcznej powinni używać tego samego systemu jednostek. Wpis nie zostanie zapisany w pamięci podręcznej, jeśli suma rozmiarów wpisów w pamięci podręcznej przekroczy wartość określoną przez SizeLimit. Jeśli nie ustawiono limitu rozmiaru pamięci podręcznej, rozmiar pamięci podręcznej ustawiony we wpisie jest ignorowany.
Następujący kod jest rejestrowany MyMemoryCache w kontenerze wstrzykiwania zależności :
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<MyMemoryCache>();
MyMemoryCache jest tworzony jako niezależna pamięć podręczna dla komponentów, które są świadome tego rozmiaru ograniczonej pamięci podręcznej i wiedzą, jak odpowiednio ustawić rozmiar wpisu pamięci podręcznej.
Rozmiar wpisu pamięci podręcznej można ustawić za pomocą SetSize metody extension lub Size właściwości:
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);
}
W poprzednim kodzie dwa wyróżnione wiersze osiągają ten sam wynik ustawiania rozmiaru wpisu pamięci podręcznej.
SetSize jest zapewniony dla wygody podczas łączenia połączeń łańcuchowych z new MemoryCacheOptions().
MemoryCache.Compact
MemoryCache.Compact Próbuje usunąć określony procent pamięci podręcznej w następującej kolejności:
- Wszystkie wygasłe przedmioty.
- Elementy według priorytetu. Elementy o najniższym priorytecie są usuwane w pierwszej kolejności.
- Najrzadziej używane obiekty.
- Przedmioty z najwcześniejszą bezwzględną datą ważności.
- Przedmioty z najwcześniejszym przesuwanym terminem wygaśnięcia.
Przypięte elementy z priorytetem NeverRemovenigdy nie są usuwane. Poniższy kod usuwa element pamięci podręcznej i wywołuje Compact metody usuwania 25% wpisów w pamięci podręcznej:
_myMemoryCache.Cache.Remove(CacheKeys.Entry);
_myMemoryCache.Cache.Compact(.25);
Aby uzyskać więcej informacji, zobacz źródło kompaktu w witrynie GitHub.
Zależności pamięci podręcznej
W poniższym przykładzie pokazano, jak wygasnąć wpis pamięci podręcznej, jeśli wpis zależny wygaśnie. A CancellationChangeToken jest dodawany do elementu w pamięci podręcznej. Gdy Cancel jest wywoływany CancellationTokenSourcew , oba wpisy pamięci podręcznej są eksmitowane:
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();
}
Użycie a CancellationTokenSource umożliwia eksmisję wielu wpisów pamięci podręcznej jako grupy. W przypadku wzorca using w powyższym kodzie wpisy pamięci podręcznej utworzone wewnątrz using zakresu dziedziczą wyzwalacze i ustawienia wygasania.
Dodatkowe uwagi
Wygaśnięcie nie następuje w tle. Nie ma czasomierza, który aktywnie skanuje pamięć podręczną w poszukiwaniu wygasłych elementów. Każda aktywność w pamięci podręcznej (
Get,TryGetValue,Set, )Removemoże wyzwolić skanowanie w tle w poszukiwaniu wygasłych elementów. Licznik czasu na (CancellationTokenSourceCancelAfter) również usuwa wpis i uruchamia skanowanie w poszukiwaniu wygasłych elementów. W poniższym przykładzie użyto CancellationTokenSource(TimeSpan) zarejestrowanego tokenu. Po wyzwoleniu tego tokenu natychmiast usuwa wpis i uruchamia wywołania zwrotne eksmisji: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); }W przypadku korzystania z wywołania zwrotnego w celu ponownego wypełnienia elementu pamięci podręcznej:
- Wiele żądań może znaleźć wartość klucza w pamięci podręcznej pustą, ponieważ wywołanie zwrotne nie zostało ukończone.
- Może to spowodować ponowne wypełnienie elementu w pamięci podręcznej przez kilka wątków.
Gdy jeden wpis pamięci podręcznej jest używany do tworzenia innego, element podrzędny kopiuje tokeny wygaśnięcia wpisu nadrzędnego i ustawienia wygaśnięcia na podstawie czasu. Element podrzędny nie wygasł przez ręczne usunięcie lub zaktualizowanie wpisu nadrzędnego.
Służy PostEvictionCallbacks do ustawiania wywołań zwrotnych, które będą uruchamiane po wykluczeniu wpisu pamięci podręcznej z pamięci podręcznej.
W przypadku większości aplikacji
IMemoryCachejest włączona. Na przykład wywołanieAddMvc,AddControllersWithViews,AddRazorPages,AddMvcCore().AddRazorViewEnginei wielu innychAdd{Service}metod wProgram.csprogramie , umożliwiaIMemoryCache. W przypadku aplikacji, które nie wywołują żadnej z powyższychAdd{Service}metod, może być konieczne wywołanie AddMemoryCacheProgram.cs.
Aktualizacja pamięci podręcznej w tle
Użyj usługi działającej w tle , takiej jak IHostedService aktualizacja pamięci podręcznej. Usługa w tle może ponownie obliczyć wpisy, a następnie przypisać je do pamięci podręcznej tylko wtedy, gdy są gotowe.
Dodatkowe zasoby
- Wyświetl lub pobierz przykładowy kod (jak pobrać)
- Buforowanie rozproszone w ASP.NET Core
- Wykrywanie zmian za pomocą tokenów zmian w programie ASP.NET Core
- Buforowanie odpowiedzi na platformie ASP.NET Core
- Oprogramowanie pośredniczące buforowania odpowiedzi w programie ASP.NET Core
- Pomocnik tagów pamięci podręcznej w ASP.NET Core MVC
- Pomocnik tagów rozproszonej pamięci podręcznej w ASP.NET Core
Wyświetl lub pobierz przykładowy kod (jak pobrać)
Podstawy buforowania
Buforowanie może znacznie poprawić wydajność i skalowalność aplikacji, zmniejszając ilość pracy wymaganą do wygenerowania zawartości. Buforowanie działa najlepiej w przypadku danych, które zmieniają się rzadko, a ich generowanie jest kosztowne. Buforowanie tworzy kopię danych, która może zostać zwrócona znacznie szybciej niż ze źródła. Aplikacje powinny być pisane i testowane tak, aby nigdy nie były zależne od danych w pamięci podręcznej.
ASP.NET Core obsługuje kilka różnych pamięci podręcznych. Najprostsza pamięć podręczna oparta jest na IMemoryCache.
IMemoryCache reprezentuje pamięć podręczną przechowywaną w pamięci serwera WWW. Aplikacje działające w farmie serwerów (wielu serwerach) powinny zapewnić, że sesje są trwałe podczas korzystania z pamięci podręcznej w pamięci. Trwałe sesje zapewniają, że wszystkie kolejne żądania od klienta trafiają do tego samego serwera. Na przykład aplikacje internetowe platformy Azure używają routingu żądań aplikacji (ARR) do kierowania wszystkich kolejnych żądań do tego samego serwera.
Sesje nietrwałe w farmie sieci Web wymagają rozproszonej pamięci podręcznej , aby uniknąć problemów ze spójnością pamięci podręcznej. W przypadku niektórych aplikacji rozproszona pamięć podręczna może obsługiwać większe skalowanie w poziomie niż pamięć podręczna w pamięci. Użycie rozproszonej pamięci podręcznej powoduje odciążenie pamięci podręcznej do procesu zewnętrznego.
W pamięci podręcznej w pamięci można przechowywać dowolny obiekt. Interfejs rozproszonej pamięci podręcznej jest ograniczony do byte[]. Pamięć podręczna w pamięci i rozproszona pamięć podręczna przechowują elementy pamięci podręcznej jako pary klucz-wartość.
System.Runtime.Caching/MemoryCache
System.Runtime.Caching / MemoryCache (pakiet NuGet) może być używany z:
- .NET Standard 2.0 lub nowszy.
- Dowolna implementacja platformy .NET przeznaczona dla platformy .NET Standard 2.0 lub nowszej. Na przykład ASP.NET Core 3.1 lub nowszy.
- .NET Framework 4.5 lub nowszy.
Microsoft.Extensions.Caching.Memory/IMemoryCache (opisany w tym artykule) jest zalecany System.Runtime.Caching/MemoryCache , ponieważ jest lepiej zintegrowany z ASP.NET Core. Na przykład IMemoryCache działa natywnie z wstrzykiwaniem zależności ASP.NET Core.
Służy System.Runtime.Caching/MemoryCache jako mostek zgodności podczas przenoszenia kodu z ASP.NET 4.x do ASP.NET Core.
Wskazówki dotyczące pamięci podręcznej
- Kod powinien zawsze mieć opcję awaryjną do pobierania danych i nie zależeć od dostępności wartości w pamięci podręcznej.
- Pamięć podręczna korzysta z rzadkiego zasobu, pamięci. Ogranicz wzrost pamięci podręcznej:
- Nie używaj zewnętrznych danych wejściowych jako kluczy pamięci podręcznej.
- Użyj wygaśnięcia, aby ograniczyć wzrost pamięci podręcznej.
- Użyj wartości SetSize, Size i SizeLimit, aby ograniczyć rozmiar pamięci podręcznej. Środowisko uruchomieniowe ASP.NET Core nie ogranicza rozmiaru pamięci podręcznej na podstawie wykorzystania pamięci. To od programisty zależy, czy ograniczy rozmiar pamięci podręcznej.
Korzystanie z usługi IMemoryCache
Warning
Użycie pamięci podręcznej pamięci współużytkowanej z iniekcji zależności i wywołanie SetSize, Sizelub SizeLimit w celu ograniczenia rozmiaru pamięci podręcznej może spowodować awarię aplikacji. Gdy w pamięci podręcznej jest ustawiony limit rozmiaru, wszystkie wpisy muszą określać rozmiar podczas dodawania. Może to prowadzić do problemów, ponieważ programiści mogą nie mieć pełnej kontroli nad tym, co korzysta z udostępnionej pamięci podręcznej.
W przypadku korzystania z SetSize, Sizelub SizeLimit w celu ograniczenia pamięci podręcznej utwórz pojedynczą pamięć podręczną do buforowania. Aby uzyskać więcej informacji i zapoznać się z przykładem, zobacz Używanie wartości SetSize, Size i SizeLimit w celu ograniczenia rozmiaru pamięci podręcznej.
Udostępniona pamięć podręczna to pamięć podręczna współużytkowana przez inne struktury lub biblioteki.
Buforowanie w pamięci to usługa , do której odwołuje się aplikacja przy użyciu wstrzykiwania zależności. Zażądaj instancji IMemoryCache w konstruktorze:
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
Poniższy kod służy TryGetValue do sprawdzania, czy czas znajduje się w pamięci podręcznej. Jeśli czas nie jest buforowany, tworzony jest nowy wpis i dodawany do pamięci podręcznej za pomocą Set. Klasa CacheKeys jest częścią przykładu pobierania.
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);
}
Wyświetlany jest bieżący czas i czas zapisany w pamięci podręcznej:
@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>
Poniższy kod używa Set metody extension do buforowania danych przez czas względny bez tworzenia obiektu 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);
}
Wartość z DateTime pamięci podręcznej pozostaje w pamięci podręcznej, gdy w okresie limitu czasu występują żądania.
Poniższy kod używa GetOrCreate and GetOrCreateAsync do buforowania danych.
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);
}
Następujące wywołania Get kodu w celu pobrania czasu w pamięci podręcznej:
public IActionResult CacheGet()
{
var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry);
return View("Cache", cacheEntry);
}
Poniższy kod pobiera lub tworzy element w pamięci podręcznej z bezwzględnym wygaśnięciem:
public IActionResult CacheGetOrCreateAbs()
{
var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
return DateTime.Now;
});
return View("Cache", cacheEntry);
}
Istnieje ryzyko, że zestaw elementów w pamięci podręcznej z przesuwanym wygaśnięciem nigdy nie wygaśnie. Jeśli element w pamięci podręcznej jest wielokrotnie otwierany w przesuwnym interwale wygasania, element nigdy nie wygasa. Połącz przesuwne wygaśnięcie z bezwzględnym wygaśnięciem, aby zagwarantować, że przedmiot wygaśnie. Bezwzględne wygaśnięcie określa górną granicę tego, jak długo element może być buforowany, jednocześnie umożliwiając wcześniejsze wygaśnięcie elementu, jeśli nie zostanie zażądany w przesuwnym interwale wygaśnięcia. Jeśli minie przesuwny interwał wygaśnięcia lub bezwzględny czas wygaśnięcia, element zostanie usunięty z pamięci podręcznej.
Poniższy kod pobiera lub tworzy element w pamięci podręcznej z wygaśnięciem przesuwnym i bezwzględnym:
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);
}
Powyższy kod gwarantuje, że dane nie będą buforowane dłużej niż czas bezwzględny.
GetOrCreate, GetOrCreateAsync, i Get są metodami rozszerzenia w CacheExtensions klasie. Metody te rozszerzają IMemoryCachemożliwości programu .
MemoryCacheEntryOptions
Poniższy przykład:
- Ustawia przesuwany czas wygaśnięcia. Żądania dostępu do tego elementu w pamięci podręcznej spowodują zresetowanie przesuwanego zegara wygaśnięcia.
- Ustawia priorytet pamięci podręcznej na CacheItemPriority.NeverRemove.
- Ustawia element, PostEvictionDelegate który zostanie wywołany po wykluczeniu wpisu z pamięci podręcznej. Wywołanie zwrotne jest uruchamiane w innym wątku niż kod, który usuwa element z pamięci podręcznej.
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);
}
Użyj SetSize, Size i SizeLimit, aby ograniczyć rozmiar pamięci podręcznej
Instancja MemoryCache może opcjonalnie określać i wymuszać limit rozmiaru. Limit rozmiaru pamięci podręcznej nie ma zdefiniowanej jednostki miary, ponieważ pamięć podręczna nie ma mechanizmu mierzenia rozmiaru wpisów. Jeśli ustawiony jest limit rozmiaru pamięci podręcznej, wszystkie wpisy muszą określać rozmiar. Środowisko uruchomieniowe ASP.NET Core nie ogranicza rozmiaru pamięci podręcznej na podstawie wykorzystania pamięci. To od programisty zależy, czy ograniczy rozmiar pamięci podręcznej. Określony rozmiar jest w jednostkach wybranych przez programistę.
Przykład:
- Jeśli aplikacja internetowa głównie buforowała ciągi, każdy rozmiar wpisu pamięci podręcznej może być długością ciągu.
- Aplikacja może określić rozmiar wszystkich wpisów jako 1, a limit rozmiaru to liczba wpisów.
Jeśli SizeLimit nie jest ustawiona, pamięć podręczna rośnie bez ograniczeń. Środowisko uruchomieniowe ASP.NET Core nie przycina pamięci podręcznej, gdy pamięć systemowa jest niska. Aplikacje muszą być zaprojektowane tak, aby:
- Ogranicz wzrost pamięci podręcznej.
- Zadzwoń Compact lub Remove gdy dostępna pamięć jest ograniczona:
Poniższy kod tworzy stały rozmiar MemoryCache bez jednostek dostępny przez wstrzyknięcie zależności:
// using Microsoft.Extensions.Caching.Memory;
public class MyMemoryCache
{
public MemoryCache Cache { get; private set; }
public MyMemoryCache()
{
Cache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 1024
});
}
}
SizeLimit nie ma jednostek. Wpisy w pamięci podręcznej muszą określać rozmiar w jednostkach, które uznają za najbardziej odpowiednie, jeśli limit rozmiaru pamięci podręcznej został ustawiony. Wszyscy użytkownicy instancji pamięci podręcznej powinni używać tego samego systemu jednostek. Wpis nie zostanie zapisany w pamięci buforowej, jeśli suma rozmiarów wpisów w pamięci podręcznej przekroczy wartość określoną przez SizeLimit. Jeśli nie zostanie ustawiony limit rozmiaru pamięci podręcznej, rozmiar pamięci podręcznej ustawiony we wpisie zostanie zignorowany.
Poniższy kod jest rejestrowany MyMemoryCache w kontenerze wstrzykiwania zależności .
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSingleton<MyMemoryCache>();
}
MyMemoryCache jest tworzony jako niezależna pamięć podręczna dla komponentów, które są świadome tego rozmiaru ograniczonej pamięci podręcznej i wiedzą, jak odpowiednio ustawić rozmiar wpisu pamięci podręcznej.
Poniższy kod używa metody 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");
}
}
Rozmiar wpisu pamięci podręcznej można ustawić za pomocą SizeSetSize lub metod rozszerzenia:
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
MemoryCache.Compact Próbuje usunąć określony procent pamięci podręcznej w następującej kolejności:
- Wszystkie wygasłe przedmioty.
- Elementy według priorytetu. Elementy o najniższym priorytecie są usuwane w pierwszej kolejności.
- Najrzadziej używane obiekty.
- Przedmioty z najwcześniejszą bezwzględną datą ważności.
- Przedmioty z najwcześniejszym przesuwanym terminem wygaśnięcia.
Przypięte elementy z priorytetem NeverRemove nigdy nie są usuwane. Poniższy kod usuwa element pamięci podręcznej i wywołuje Compact:
_cache.Remove(MyKey);
// Remove 33% of cached items.
_cache.Compact(.33);
cache_size = _cache.Count;
Aby uzyskać więcej informacji, zobacz źródło kompaktu w witrynie GitHub.
Zależności pamięci podręcznej
W poniższym przykładzie pokazano, jak wygasnąć wpis pamięci podręcznej, jeśli wpis zależny wygaśnie. A CancellationChangeToken jest dodawany do elementu w pamięci podręcznej. Gdy Cancel zostanie wywołany CancellationTokenSourcew , oba wpisy pamięci podręcznej są eksmitowane.
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);
}
Użycie a CancellationTokenSource umożliwia eksmisję wielu wpisów pamięci podręcznej jako grupy. W przypadku wzorca using w powyższym kodzie wpisy pamięci podręcznej utworzone wewnątrz using bloku będą dziedziczyć wyzwalacze i ustawienia wygasania.
Dodatkowe uwagi
Wygaśnięcie nie następuje w tle. Nie ma timera, który aktywnie skanuje pamięć podręczną w poszukiwaniu wygasłych elementów. Każda aktywność w pamięci podręcznej (
Get,Set,Remove) może wyzwolić skanowanie w tle w poszukiwaniu wygasłych elementów. Licznik czasu na (CancellationTokenSourceCancelAfter) również usuwa wpis i uruchamia skanowanie w poszukiwaniu wygasłych elementów. W poniższym przykładzie użyto CancellationTokenSource(TimeSpan) zarejestrowanego tokenu. Po wyzwoleniu tego tokenu natychmiast usuwa wpis i uruchamia wywołania zwrotne eksmisji: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); }W przypadku korzystania z wywołania zwrotnego w celu ponownego wypełnienia elementu pamięci podręcznej:
- Wiele żądań może znaleźć wartość klucza w pamięci podręcznej pustą, ponieważ wywołanie zwrotne nie zostało ukończone.
- Może to spowodować ponowne wypełnienie elementu w pamięci podręcznej przez kilka wątków.
Gdy jeden wpis pamięci podręcznej jest używany do tworzenia innego, element podrzędny kopiuje tokeny wygaśnięcia wpisu nadrzędnego i ustawienia wygaśnięcia na podstawie czasu. Element podrzędny nie wygasł przez ręczne usunięcie lub zaktualizowanie wpisu nadrzędnego.
Służy PostEvictionCallbacks do ustawiania wywołań zwrotnych, które będą uruchamiane po wykluczeniu wpisu pamięci podręcznej z pamięci podręcznej. W przykładowym kodzie CancellationTokenSource.Dispose() jest wywoływana w celu zwolnienia niezarządzanych zasobów używanych przez
CancellationTokenSource. Jednak nieCancellationTokenSourcejest on usuwany natychmiast, ponieważ jest nadal używany przez wpis pamięci podręcznej. JestCancellationTokenprzekazywany doMemoryCacheEntryOptions, aby utworzyć wpis pamięci podręcznej, który wygasa po określonym czasie. DlategoDisposenie należy go wywoływać, dopóki wpis pamięci podręcznej nie zostanie usunięty lub nie wygaśnie. Przykładowy RegisterPostEvictionCallback kod wywołuje metodę w celu zarejestrowania wywołania zwrotnego, które zostanie wywołane, gdy wpis pamięci podręcznej zostanie eksmitowany, i usuwa wCancellationTokenSourcetym wywołaniu zwrotnym.W przypadku większości aplikacji
IMemoryCachejest włączona. Na przykład wywołanieAddMvc,AddControllersWithViews,AddRazorPages,AddMvcCore().AddRazorViewEnginei wielu innychAdd{Service}metod wConfigureServicesprogramie , umożliwiaIMemoryCache. W przypadku aplikacji, które nie wywołują żadnej z powyższychAdd{Service}metod, może być konieczne wywołanie AddMemoryCacheConfigureServices.
Aktualizacja pamięci podręcznej w tle
Użyj usługi działającej w tle , takiej jak IHostedService aktualizacja pamięci podręcznej. Usługa w tle może ponownie obliczyć wpisy, a następnie przypisać je do pamięci podręcznej tylko wtedy, gdy są gotowe.
Dodatkowe zasoby
- Buforowanie rozproszone w ASP.NET Core
- Wykrywanie zmian za pomocą tokenów zmian w programie ASP.NET Core
- Buforowanie odpowiedzi na platformie ASP.NET Core
- Oprogramowanie pośredniczące buforowania odpowiedzi w programie ASP.NET Core
- Pomocnik tagów pamięci podręcznej w ASP.NET Core MVC
- Pomocnik tagów rozproszonej pamięci podręcznej w ASP.NET Core