Auf Englisch lesen

Freigeben über


Erstellen von vorberechneten Aufgaben

Dieser Artikel beschreibt, wie mithilfe der Task.FromResult-Methode die Ergebnisse asynchroner Downloadvorgänge aus einem Cache abgerufen werden können. Die FromResult-Methode gibt ein fertig gestelltes Task<TResult>-Objekt zurück, das den angegebenen Wert als Result-Eigenschaft enthält. Diese Methode ist nützlich, wenn Sie einen asynchronen Vorgang ausführen, der ein Task<TResult>-Objekt zurückgibt, und das Ergebnis dieses Task<TResult>-Objekts bereits berechnet wurde.

Beispiel

Im folgenden Beispiel werden Zeichenfolgen aus dem Web heruntergeladen. Es definiert die DownloadStringAsync-Methode. Diese Methode lädt Zeichenfolgen asynchron aus dem Web herunter. In diesem Beispiel wird außerdem ein ConcurrentDictionary<TKey,TValue>-Objekt verwendet, um die Ergebnisse vorangegangener Vorgänge zwischenzuspeichern. Wenn die Eingabeadresse in diesem Cache gespeichert wird, verwendet DownloadStringAsync die FromResult-Methode zum Erzeugen eines Task<TResult>-Objekts, das den Inhalt an dieser Adresse beibehält. Andernfalls lädt DownloadStringAsync die Datei aus dem Web herunter und fügt das Ergebnis dem Cache hinzu.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

public static class DownloadCache
{
    private static readonly ConcurrentDictionary<string, string> s_cachedDownloads = new();
    private static readonly HttpClient s_httpClient = new();

    public static Task<string> DownloadStringAsync(string address)
    {
        if (s_cachedDownloads.TryGetValue(address, out string? content))
        {
            return Task.FromResult(content);
        }

        return Task.Run(async () =>
        {
            content = await s_httpClient.GetStringAsync(address);
            s_cachedDownloads.TryAdd(address, content);

            return content;
        });
    }

    public static async Task Main()
    {
        string[] urls = new[]
        {
            "https://learn.microsoft.com/aspnet/core",
            "https://learn.microsoft.com/dotnet",
            "https://learn.microsoft.com/dotnet/architecture/dapr-for-net-developers",
            "https://learn.microsoft.com/dotnet/azure",
            "https://learn.microsoft.com/dotnet/desktop/wpf",
            "https://learn.microsoft.com/dotnet/devops/create-dotnet-github-action",
            "https://learn.microsoft.com/dotnet/machine-learning",
            "https://learn.microsoft.com/xamarin",
            "https://dotnet.microsoft.com/",
            "https://www.microsoft.com"
        };

        Stopwatch stopwatch = Stopwatch.StartNew();
        IEnumerable<Task<string>> downloads = urls.Select(DownloadStringAsync);

        static void StopAndLogElapsedTime(
            int attemptNumber, Stopwatch stopwatch, Task<string[]> downloadTasks)
        {
            stopwatch.Stop();

            int charCount = downloadTasks.Result.Sum(result => result.Length);
            long elapsedMs = stopwatch.ElapsedMilliseconds;

            Console.WriteLine(
                $"Attempt number: {attemptNumber}\n" +
                $"Retrieved characters: {charCount:#,0}\n" +
                $"Elapsed retrieval time: {elapsedMs:#,0} milliseconds.\n");
        }

        await Task.WhenAll(downloads).ContinueWith(
            downloadTasks => StopAndLogElapsedTime(1, stopwatch, downloadTasks));

        // Perform the same operation a second time. The time required
        // should be shorter because the results are held in the cache.
        stopwatch.Restart();

        downloads = urls.Select(DownloadStringAsync);

        await Task.WhenAll(downloads).ContinueWith(
            downloadTasks => StopAndLogElapsedTime(2, stopwatch, downloadTasks));
    }
    // Sample output:
    //     Attempt number: 1
    //     Retrieved characters: 754,585
    //     Elapsed retrieval time: 2,857 milliseconds.

    //     Attempt number: 2
    //     Retrieved characters: 754,585
    //     Elapsed retrieval time: 1 milliseconds.
}

Im vorherigen Beispiel wird der Wert beim ersten Herunterladen jeder URL im Cache gespeichert. Die FromResult-Methode ermöglicht der DownloadStringAsync-Methode, Task<TResult>-Objekte zu erstellen, die diese vorberechneten Ergebnisse enthalten. Nachfolgende Aufrufe zum Herunterladen der Zeichenfolge geben die zwischengespeicherten Werte zurück und sind viel schneller.

Siehe auch