Freigeben über


Zwischenspeichern in .NET

In diesem Artikel erfahren Sie mehr über verschiedene Zwischenspeicherungsmechanismen. Zwischenspeichern ist das Speichern von Daten in einer Zwischenschicht, wodurch nachfolgende Datenabrufe schneller erfolgen. Konzeptuell ist Caching eine Strategie zur Leistungsoptimierung und Designüberlegung. Das Zwischenspeichern kann die App-Leistung erheblich verbessern, indem selten geänderte (oder teure) Daten leichter verfügbar sind. In diesem Artikel werden die beiden primären Cachetypen vorgestellt, und es werden Beispielquellcode für beides bereitgestellt:

Von Bedeutung

Es gibt zwei MemoryCache Klassen in .NET, eine im System.Runtime.Caching Namespace und die andere im Microsoft.Extensions.Caching Namespace:

Dieser Artikel konzentriert sich zwar auf das Zwischenspeichern, enthält aber nicht das System.Runtime.Caching NuGet-Paket. Alle Verweise zu MemoryCache befinden sich im Microsoft.Extensions.Caching Namensraum.

Alle Microsoft.Extensions.* Pakete sind für die Abhängigkeitsinjektion (DI) bereit, sowohl die IMemoryCache als auch die IDistributedCache Schnittstellen können als Dienste genutzt werden.

In-Memory-Caching

In diesem Abschnitt erfahren Sie mehr über das Microsoft.Extensions.Caching.Memory-Paket . Die aktuelle Implementierung von IMemoryCache ist ein Wrapper um das ConcurrentDictionary<TKey,TValue>, wobei eine funktionsreiche API verfügbar gemacht wird. Einträge innerhalb des Caches werden durch das ICacheEntry dargestellt und können beliebig object sein. Die In-Memory-Cachelösung eignet sich hervorragend für Apps, die auf einem einzelnen Server ausgeführt werden, auf dem alle zwischengespeicherten Daten Arbeitsspeicher im Prozess der App belegen.

Tipp

Berücksichtigen Sie bei Szenarien mit multiserverbasiertem Zwischenspeichern den Ansatz für die verteilte Zwischenspeicherung als Alternative zur Zwischenspeicherung im Arbeitsspeicher.

Zwischenspeicherungs-API im RAM

Der Verbraucher des Caches hat Kontrolle über sowohl gleitende als auch absolute Ablaufzeiten.

Das Festlegen eines Ablaufs führt dazu, dass Einträge im Cache entfernt werden, wenn nicht innerhalb der zugewiesenen Ablaufzeit auf sie zugegriffen wird. Verbraucher haben zusätzliche Optionen zum Verwalten von Cacheeinträgen durch die MemoryCacheEntryOptions. Jeder ICacheEntry ist mit MemoryCacheEntryOptions gekoppelt, wodurch die Funktionalität zum Entfernen von Ablaufzeit mit IChangeToken, Prioritätseinstellungen mit CacheItemPriority und das Steuern des ICacheEntry.Size verfügbar gemacht werden. Berücksichtigen Sie die folgenden Erweiterungsmethoden:

Beispiel für in-Memory-Cache

Um die Standardimplementierung IMemoryCache zu verwenden, rufen Sie die AddMemoryCache Erweiterungsmethode auf, um alle erforderlichen Dienste bei DI zu registrieren. Im folgenden Codebeispiel wird der generische Host verwendet, um DI-Funktionen verfügbar zu machen:

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();

Abhängig von Ihrer .NET-Workload können Sie anders auf den IMemoryCache zugreifen, z. B. als Konstruktorinjektion. In diesem Beispiel verwenden Sie die IServiceProvider Instanz auf der host und rufen die generische GetRequiredService<T>(IServiceProvider) Erweiterungsmethode auf.

IMemoryCache cache =
    host.Services.GetRequiredService<IMemoryCache>();

Mit registrierten In-Memory-Cachediensten und aufgelöst über DI – Sie können mit dem Zwischenspeichern beginnen. Im Beispiel werden im englischen Alphabet die Buchstaben „A“ bis „Z“ durchlaufen. Der record AlphabetLetter Typ enthält den Verweis auf den Brief und generiert eine Nachricht.

file record AlphabetLetter(char Letter)
{
    internal string Message =>
        $"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}

Tipp

Der file Zugriffsmodifizierer wird für den AlphabetLetter Typ verwendet, da er innerhalb definiert ist und nur über die Program.cs Datei darauf zugegriffen wird. Weitere Informationen finden Sie in der Datei (C#-Referenz). Informationen zum vollständigen Quellcode finden Sie im Abschnitt Program.cs .

Das Beispiel enthält eine Hilfsfunktion, die durch die Buchstaben des Alphabets iteriert.

static async ValueTask IterateAlphabetAsync(
    Func<char, Task> asyncFunc)
{
    for (char letter = 'A'; letter <= 'Z'; ++letter)
    {
        await asyncFunc(letter);
    }

    Console.WriteLine();
}

Im oben stehenden C#-Code ist Folgendes passiert:

  • Die Func<char, Task> asyncFunc wird bei jeder Iteration erwartet, wobei der aktuelle letter übergeben wird.
  • Nachdem alle Buchstaben verarbeitet wurden, wird eine leere Zeile in die Konsole geschrieben.

So fügen Sie Elemente dem Cache hinzu, indem Sie eines der Create APIs oder Set APIs aufrufen.

var addLettersToCacheTask = IterateAlphabetAsync(letter =>
{
    MemoryCacheEntryOptions options = new()
    {
        AbsoluteExpirationRelativeToNow =
            TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
    };

    _ = options.RegisterPostEvictionCallback(OnPostEviction);

    AlphabetLetter alphabetLetter =
        cache.Set(
            letter, new AlphabetLetter(letter), options);

    Console.WriteLine($"{alphabetLetter.Letter} was cached.");

    return Task.Delay(
        TimeSpan.FromMilliseconds(MillisecondsDelayAfterAdd));
});
await addLettersToCacheTask;

Im oben stehenden C#-Code ist Folgendes passiert:

  • Die Variable addLettersToCacheTask delegiert an IterateAlphabetAsync und wird benötigt.
  • Func<char, Task> asyncFunc ist durch eine Lambda-Funktion vertreten.
  • MemoryCacheEntryOptions wird mit einem zum aktuellen Zeitpunkt relativen absoluten Ablauf instanziiert.
  • Ein Rückruf nach dem Entfernen wird registriert.
  • Ein AlphabetLetter Objekt wird instanziiert und zusammen mit Set und letter in options übergeben.
  • Der Buchstabe wird als zwischengespeichert in die Konsole geschrieben.
  • Schließlich wird ein Task.Delay Wert zurückgegeben.

Für jeden Buchstaben im Alphabet wird ein Cacheeintrag mit einem Ablauf und Rückruf nach dem Entfernen geschrieben.

Der Rückruf nach dem Entfernen schreibt die Details des entfernten Werts in die Konsole:

static void OnPostEviction(
    object key, object? letter, EvictionReason reason, object? state)
{
    if (letter is AlphabetLetter alphabetLetter)
    {
        Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
    }
};

Nach dem Auffüllen des Caches wird ein weiterer Aufruf von IterateAlphabetAsync erwartet, aber dieses Mal rufen Sie IMemoryCache.TryGetValue auf:

var readLettersFromCacheTask = IterateAlphabetAsync(letter =>
{
    if (cache.TryGetValue(letter, out object? value) &&
        value is AlphabetLetter alphabetLetter)
    {
        Console.WriteLine($"{letter} is still in cache. {alphabetLetter.Message}");
    }

    return Task.CompletedTask;
});
await readLettersFromCacheTask;

Wenn der cache den letter Schlüssel enthält und value eine Instanz eines AlphabetLetter ist, wird diese in die Konsole geschrieben. Wenn sich der letter-Schlüssel nicht im Cache befindet, wurde er entfernt, und der Rückruf nach dem Entfernen wurde aufgerufen.

Zusätzliche Erweiterungsmethoden

Das IMemoryCache kommt mit vielen komfortbasierten Erweiterungsmethoden, einschließlich einer asynchronen GetOrCreateAsync:

Alles zusammenfügen

Der gesamte Beispiel-App-Quellcode ist ein Programm der obersten Ebene und erfordert zwei NuGet-Pakete:

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMemoryCache();
using IHost host = builder.Build();

IMemoryCache cache =
    host.Services.GetRequiredService<IMemoryCache>();

const int MillisecondsDelayAfterAdd = 50;
const int MillisecondsAbsoluteExpiration = 750;

static void OnPostEviction(
    object key, object? letter, EvictionReason reason, object? state)
{
    if (letter is AlphabetLetter alphabetLetter)
    {
        Console.WriteLine($"{alphabetLetter.Letter} was evicted for {reason}.");
    }
};

static async ValueTask IterateAlphabetAsync(
    Func<char, Task> asyncFunc)
{
    for (char letter = 'A'; letter <= 'Z'; ++letter)
    {
        await asyncFunc(letter);
    }

    Console.WriteLine();
}

var addLettersToCacheTask = IterateAlphabetAsync(letter =>
{
    MemoryCacheEntryOptions options = new()
    {
        AbsoluteExpirationRelativeToNow =
            TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
    };

    _ = options.RegisterPostEvictionCallback(OnPostEviction);

    AlphabetLetter alphabetLetter =
        cache.Set(
            letter, new AlphabetLetter(letter), options);

    Console.WriteLine($"{alphabetLetter.Letter} was cached.");

    return Task.Delay(
        TimeSpan.FromMilliseconds(MillisecondsDelayAfterAdd));
});
await addLettersToCacheTask;

var readLettersFromCacheTask = IterateAlphabetAsync(letter =>
{
    if (cache.TryGetValue(letter, out object? value) &&
        value is AlphabetLetter alphabetLetter)
    {
        Console.WriteLine($"{letter} is still in cache. {alphabetLetter.Message}");
    }

    return Task.CompletedTask;
});
await readLettersFromCacheTask;

await host.RunAsync();

file record AlphabetLetter(char Letter)
{
    internal string Message =>
        $"The '{Letter}' character is the {Letter - 64} letter in the English alphabet.";
}

Sie können die Werte MillisecondsDelayAfterAdd und MillisecondsAbsoluteExpiration anpassen, um die Verhaltensänderungen beim Ablauf und beim Entfernen von zwischengespeicherten Einträgen zu beobachten. Im Folgenden sehen Sie eine Beispielausgabe aus der Ausführung dieses Codes. Aufgrund der nicht deterministischen Natur von .NET-Ereignissen kann ihre Ausgabe unterschiedlich sein.

A was cached.
B was cached.
C was cached.
D was cached.
E was cached.
F was cached.
G was cached.
H was cached.
I was cached.
J was cached.
K was cached.
L was cached.
M was cached.
N was cached.
O was cached.
P was cached.
Q was cached.
R was cached.
S was cached.
T was cached.
U was cached.
V was cached.
W was cached.
X was cached.
Y was cached.
Z was cached.

A was evicted for Expired.
C was evicted for Expired.
B was evicted for Expired.
E was evicted for Expired.
D was evicted for Expired.
F was evicted for Expired.
H was evicted for Expired.
K was evicted for Expired.
L was evicted for Expired.
J was evicted for Expired.
G was evicted for Expired.
M was evicted for Expired.
N was evicted for Expired.
I was evicted for Expired.
P was evicted for Expired.
R was evicted for Expired.
O was evicted for Expired.
Q was evicted for Expired.
S is still in cache. The 'S' character is the 19 letter in the English alphabet.
T is still in cache. The 'T' character is the 20 letter in the English alphabet.
U is still in cache. The 'U' character is the 21 letter in the English alphabet.
V is still in cache. The 'V' character is the 22 letter in the English alphabet.
W is still in cache. The 'W' character is the 23 letter in the English alphabet.
X is still in cache. The 'X' character is the 24 letter in the English alphabet.
Y is still in cache. The 'Y' character is the 25 letter in the English alphabet.
Z is still in cache. The 'Z' character is the 26 letter in the English alphabet.

Da das absolute Ablaufdatum (MemoryCacheEntryOptions.AbsoluteExpirationRelativeToNow) festgelegt ist, werden alle zwischengespeicherten Elemente letztendlich entfernt.

Zwischenspeichern des Workerdiensts

Eine gängige Strategie zum Zwischenspeichern von Daten ist das Aktualisieren des Caches unabhängig von den verbrauchenden Datendiensten. Die Workerdienst-Vorlage ist ein gutes Beispiel, da der BackgroundService unabhängig vom übrigen Anwendungscode (d. h. im Hintergrund) ausgeführt wird. Wenn eine Anwendung gestartet wird, die eine Implementierung von IHostedService hostet, wird die entsprechende Implementierung (in diesem Fall BackgroundService oder Worker) innerhalb desselben Prozesses ausgeführt. Diese gehosteten Dienste werden über die AddHostedService<THostedService>(IServiceCollection) Erweiterungsmethode als Singletons bei DI registriert. Andere Dienste können bei DI mit jeder Dienstlebensdauer registriert werden.

Von Bedeutung

Es ist sehr wichtig, mit der Lebensdauer des Diensts vertraut zu sein. Wenn AddMemoryCache aufgerufen wird, um alle In-Memory-Caching-Dienste zu registrieren, werden die Dienste als Singletons registriert.

Fotodienstszenario

Stellen Sie sich vor, Sie entwickeln einen Fotodienst, der auf eine Drittanbieter-API angewiesen ist und über HTTP zugänglich ist. Diese Fotodaten ändern sich nicht sehr oft, aber es gibt viele davon. Jedes Foto wird durch ein einfaches recordDargestellt:

namespace CachingExamples.Memory;

public readonly record struct Photo(
    int AlbumId,
    int Id,
    string Title,
    string Url,
    string ThumbnailUrl);

Im folgenden Beispiel werden mehrere Dienste angezeigt, die bei DI registriert werden. Jeder Dienst hat eine einzige Verantwortung.

using CachingExamples.Memory;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddMemoryCache();
builder.Services.AddHttpClient<CacheWorker>();
builder.Services.AddHostedService<CacheWorker>();
builder.Services.AddScoped<PhotoService>();
builder.Services.AddSingleton(typeof(CacheSignal<>));

using IHost host = builder.Build();

await host.StartAsync();

Im oben stehenden C#-Code ist Folgendes passiert:

Dies PhotoService ist für das Abrufen von Fotos verantwortlich, die bestimmten Kriterien entsprechen (oder filter):

using Microsoft.Extensions.Caching.Memory;

namespace CachingExamples.Memory;

public sealed class PhotoService(
        IMemoryCache cache,
        CacheSignal<Photo> cacheSignal,
        ILogger<PhotoService> logger)
{
    public async IAsyncEnumerable<Photo> GetPhotosAsync(Func<Photo, bool>? filter = default)
    {
        try
        {
            await cacheSignal.WaitAsync();

            Photo[] photos =
                (await cache.GetOrCreateAsync(
                    "Photos", _ =>
                    {
                        logger.LogWarning("This should never happen!");

                        return Task.FromResult(Array.Empty<Photo>());
                    }))!;

            // If no filter is provided, use a pass-thru.
            filter ??= _ => true;

            foreach (Photo photo in photos)
            {
                if (!default(Photo).Equals(photo) && filter(photo))
                {
                    yield return photo;
                }
            }
        }
        finally
        {
            cacheSignal.Release();
        }
    }
}

Im oben stehenden C#-Code ist Folgendes passiert:

  • Der Konstruktor erfordert ein IMemoryCache, CacheSignal<Photo>und ILogger.
  • Die GetPhotosAsync Methode:
    • Definiert einen Func<Photo, bool> filter-Parameter und gibt ein IAsyncEnumerable<Photo> zurück.
    • Ruft an und wartet darauf, dass _cacheSignal.WaitAsync() freigegeben wird, damit sichergestellt ist, dass der Cache aufgefüllt wird, bevor darauf zugegriffen wird.
    • Ruft _cache.GetOrCreateAsync() auf, und ruft asynchron alle Fotos im Cache ab.
    • Das factory Argument protokolliert eine Warnung und gibt ein leeres Fotoarray zurück – dies sollte nie geschehen.
    • Jedes Foto im Cache wird durchlaufen, gefiltert und mit yield return angezeigt.
    • Schließlich wird das Cachesignal zurückgesetzt.

Nutzer dieses Dienstes können die GetPhotosAsync-Methode aufrufen und Fotos entsprechend bearbeiten. Nein HttpClient ist erforderlich, da der Cache die Fotos enthält.

Das asynchrone Signal basiert auf einer gekapselten SemaphoreSlim Instanz innerhalb eines generisch eingeschränkten Singletons. Dies CacheSignal<T> basiert auf einer Instanz von SemaphoreSlim:

namespace CachingExamples.Memory;

public sealed class CacheSignal<T>
{
    private readonly SemaphoreSlim _semaphore = new(1, 1);

    /// <summary>
    /// Exposes a <see cref="Task"/> that represents the asynchronous wait operation.
    /// When signaled (consumer calls <see cref="Release"/>), the 
    /// <see cref="Task.Status"/> is set as <see cref="TaskStatus.RanToCompletion"/>.
    /// </summary>
    public Task WaitAsync() => _semaphore.WaitAsync();

    /// <summary>
    /// Exposes the ability to signal the release of the <see cref="WaitAsync"/>'s operation.
    /// Callers who were waiting, will be able to continue.
    /// </summary>
    public void Release() => _semaphore.Release();
}

Im vorhergehenden C#-Code wird das Dekorator-Muster verwendet, um eine Instanz von SemaphoreSlim einzuwickeln. Da CacheSignal<T> als Singleton registriert ist, kann es in allen Dienstlebensdauern mit jedem generischen Typ verwendet werden, in diesem Fall mit Photo. Es ist für das Signalisieren des Seedings des Caches verantwortlich.

Dies CacheWorker ist eine Unterklasse von BackgroundService:

using System.Net.Http.Json;
using Microsoft.Extensions.Caching.Memory;

namespace CachingExamples.Memory;

public sealed class CacheWorker(
    ILogger<CacheWorker> logger,
    HttpClient httpClient,
    CacheSignal<Photo> cacheSignal,
    IMemoryCache cache) : BackgroundService
{
    private readonly TimeSpan _updateInterval = TimeSpan.FromHours(3);

    private bool _isCacheInitialized = false;

    private const string Url = "https://jsonplaceholder.typicode.com/photos";

    public override async Task StartAsync(CancellationToken cancellationToken)
    {
        await cacheSignal.WaitAsync();
        await base.StartAsync(cancellationToken);
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            logger.LogInformation("Updating cache.");

            try
            {
                Photo[]? photos =
                    await httpClient.GetFromJsonAsync<Photo[]>(
                        Url, stoppingToken);

                if (photos is { Length: > 0 })
                {
                    cache.Set("Photos", photos);
                    logger.LogInformation(
                        "Cache updated with {Count:#,#} photos.", photos.Length);
                }
                else
                {
                    logger.LogWarning(
                        "Unable to fetch photos to update cache.");
                }
            }
            finally
            {
                if (!_isCacheInitialized)
                {
                    cacheSignal.Release();
                    _isCacheInitialized = true;
                }
            }

            try
            {
                logger.LogInformation(
                    "Will attempt to update the cache in {Hours} hours from now.",
                    _updateInterval.Hours);

                await Task.Delay(_updateInterval, stoppingToken);
            }
            catch (OperationCanceledException)
            {
                logger.LogWarning("Cancellation acknowledged: shutting down.");
                break;
            }
        }
    }
}

Im oben stehenden C#-Code ist Folgendes passiert:

  • Der Konstruktor erfordert ein ILogger, HttpClientund IMemoryCache.
  • Dies _updateInterval ist für drei Stunden definiert.
  • Die ExecuteAsync Methode:
    • Führt während der Ausführung der App Schleifendurchläufe durch.
    • Stellt eine HTTP-Anforderung an "https://jsonplaceholder.typicode.com/photos"und ordnet die Antwort als Array von Photo Objekten zu.
    • Das Array von Fotos wird im IMemoryCache unter dem "Photos"-Schlüssel platziert.
    • _cacheSignal.Release() wird aufgerufen und gibt alle Nutzer frei, die auf das Signal gewartet haben.
    • Der Aufruf von Task.Delay wird erwartet, wenn das Aktualisierungsintervall angegeben ist.
    • Nach einer Verzögerung von drei Stunden wird der Cache erneut aktualisiert.

Consumer im selben Prozess können IMemoryCache nach den Fotos fragen, aber der CacheWorker ist für die Aktualisierung des Caches verantwortlich.

Verteiltes Zwischenspeichern

In einigen Szenarien ist ein verteilter Cache erforderlich , z. B. bei mehreren App-Servern. Ein verteilter Cache unterstützt eine höhere Skalierung als der In-Memory-Cache-Ansatz. Durch die Verwendung eines verteilten Caches wird der Cachespeicher in einen externen Prozess entladen, erfordert jedoch zusätzliche Netzwerk-E/A und führt etwas mehr Latenz ein (auch wenn nominal).

Die verteilten Zwischenspeicherungsabstraktionen sind Teil des Microsoft.Extensions.Caching.Memory NuGet-Pakets, und es gibt sogar eine AddDistributedMemoryCache Erweiterungsmethode.

Vorsicht

Dies AddDistributedMemoryCache sollte nur in Entwicklungs- und/oder Testszenarien verwendet werden und ist keine praktikable Produktionsimplementierung.

Betrachten Sie eine der verfügbaren Implementierungen des IDistributedCache aus den folgenden Paketen:

Api für verteilte Zwischenspeicherung

Die verteilten Cache-APIs sind etwas primitiver als ihre In-Memory-Cache-API-Entsprechungen. Die Schlüsselwertpaare sind etwas einfacher. Im Arbeitsspeicher basieren Zwischenspeicher-Schlüssel auf einem object, während verteilter Schlüssel ein string sind. Bei der Zwischenspeicherung im Arbeitsspeicher kann der Wert ein beliebiger stark typisierter generischer Typ sein, während die Werte in verteilten Zwischenspeicherungen als byte[] gespeichert werden. Das heißt nicht, dass verschiedene Implementierungen keine stark typierten generischen Werte verfügbar machen, dies wäre jedoch ein Implementierungsdetail.

Erstellen von Werten

Rufen Sie zum Erstellen von Werten im verteilten Cache eine der festgelegten APIs auf:

Mit dem AlphabetLetter Eintrag aus dem Beispiel des Speichercaches können Sie das Objekt in JSON serialisieren und dann string als byte[] codieren.

DistributedCacheEntryOptions options = new()
{
    AbsoluteExpirationRelativeToNow =
        TimeSpan.FromMilliseconds(MillisecondsAbsoluteExpiration)
};

AlphabetLetter alphabetLetter = new(letter);
string json = JsonSerializer.Serialize(alphabetLetter);
byte[] bytes = Encoding.UTF8.GetBytes(json);

await cache.SetAsync(letter.ToString(), bytes, options);

Ähnlich wie beim Zwischenspeichern im Arbeitsspeicher können Cacheeinträge Optionen haben, um das Vorhandensein im Cache zu optimieren – in diesem Fall die DistributedCacheEntryOptions.

Erstellen von Erweiterungsmethoden

Es gibt mehrere Erweiterungsmethoden zur bequemen Erstellung von Werten, die helfen, die Codierung von Darstellungen string von Objekten in eine byte[] zu vermeiden.

Werte lesen

Rufen Sie eine der get-APIs auf, um Werte aus dem verteilten Cache zu lesen:

AlphabetLetter? alphabetLetter = null;
byte[]? bytes = await cache.GetAsync(letter.ToString());
if (bytes is { Length: > 0 })
{
    string json = Encoding.UTF8.GetString(bytes);
    alphabetLetter = JsonSerializer.Deserialize<AlphabetLetter>(json);
}

Sobald ein Cacheeintrag aus dem Cache gelesen wurde, können Sie die UTF-8-codierte string Darstellung aus der byte[] erhalten.

Lesen von Erweiterungsmethoden

Es gibt mehrere benutzerfreundliche Erweiterungsmethoden zum Lesen von Werten, die dazu beitragen, die Decodierung byte[] in string Darstellungen von Objekten zu vermeiden:

Aktualisieren von Werten

Es gibt keine Möglichkeit, die Werte im verteilten Cache mit einem einzelnen API-Aufruf zu aktualisieren. Stattdessen können Werte ihre gleitenden Ablaufvorgänge mit einer der Aktualisierungs-APIs zurücksetzen lassen:

Wenn der tatsächliche Wert aktualisiert werden muss, müssen Sie den Wert löschen und dann erneut hinzufügen.

Löschen von Werten

Rufen Sie zum Löschen von Werten im verteilten Cache eine der entfernten APIs auf:

Tipp

Obwohl es synchrone Versionen der oben genannten APIs gibt, berücksichtigen Sie bitte die Tatsache, dass Implementierungen von verteilten Caches auf Netzwerk-E/A angewiesen sind. Aus diesem Grund werden häufiger als nicht die asynchronen APIs bevorzugt.

Siehe auch