Sdílet prostřednictvím


Zrušení seznamu úloh

Asynchronní konzolovou aplikaci můžete zrušit, pokud nechcete čekat na dokončení. Podle příkladu v tomto tématu můžete přidat zrušení do aplikace, která stáhne obsah seznamu webů. Mnoho úkolů můžete zrušit přidružením CancellationTokenSource instance k jednotlivým úkolům. Pokud vyberete klávesu Enter , zrušíte všechny úkoly, které ještě nejsou dokončené.

Tento kurz zahrnuje:

  • Vytvoření konzolové aplikace .NET
  • Psaní asynchronní aplikace, která umožňuje zrušení
  • Předvádění rušení signálu

Požadavky

Vytvoření ukázkové aplikace

Vytvořte novou konzolovou aplikaci .NET Core. Můžete ho vytvořit pomocí příkazu dotnet new console nebo sady Visual Studio. Otevřete soubor Program.cs ve svém oblíbeném editoru kódu.

Nahrazení směrnic using

Nahraďte stávající using direktivy těmito deklaracemi:

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

Přidat pole

Program Do definice třídy přidejte tato tři pole:

static readonly CancellationTokenSource s_cts = new CancellationTokenSource();

static readonly HttpClient s_client = new HttpClient
{
    MaxResponseContentBufferSize = 1_000_000
};

static readonly IEnumerable<string> s_urlList = new string[]
{
    "https://learn.microsoft.com",
    "https://learn.microsoft.com/aspnet/core",
    "https://learn.microsoft.com/azure",
    "https://learn.microsoft.com/azure/devops",
    "https://learn.microsoft.com/dotnet",
    "https://learn.microsoft.com/dynamics365",
    "https://learn.microsoft.com/education",
    "https://learn.microsoft.com/enterprise-mobility-security",
    "https://learn.microsoft.com/gaming",
    "https://learn.microsoft.com/graph",
    "https://learn.microsoft.com/microsoft-365",
    "https://learn.microsoft.com/office",
    "https://learn.microsoft.com/powershell",
    "https://learn.microsoft.com/sql",
    "https://learn.microsoft.com/surface",
    "https://learn.microsoft.com/system-center",
    "https://learn.microsoft.com/visualstudio",
    "https://learn.microsoft.com/windows",
    "https://learn.microsoft.com/maui"
};

K signalizaci požadovaného zrušení u CancellationToken se používá CancellationTokenSource. Zpřístupňuje HttpClient schopnost odesílat požadavky HTTP a přijímat odpovědi HTTP. Obsahuje s_urlList všechny adresy URL, které aplikace plánuje zpracovat.

Aktualizace vstupního bodu aplikace

Hlavním vstupním bodem do konzolové aplikace je Main metoda. Nahraďte existující metodu následujícím kódem:

static async Task Main()
{
    Console.WriteLine("Application started.");
    Console.WriteLine("Press the ENTER key to cancel...\n");

    Task cancelTask = Task.Run(() =>
    {
        while (Console.ReadKey().Key != ConsoleKey.Enter)
        {
            Console.WriteLine("Press the ENTER key to cancel...");
        }

        Console.WriteLine("\nENTER key pressed: cancelling downloads.\n");
        s_cts.Cancel();
    });

    Task sumPageSizesTask = SumPageSizesAsync();

    Task finishedTask = await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
    if (finishedTask == cancelTask)
    {
        // wait for the cancellation to take place:
        try
        {
            await sumPageSizesTask;
            Console.WriteLine("Download task completed before cancel request was processed.");
        }
        catch (TaskCanceledException)
        {
            Console.WriteLine("Download task has been cancelled.");
        }
    }

    Console.WriteLine("Application ending.");
}

Aktualizovaná metoda Main je nyní považována za Async main, což umožňuje asynchronní vstupní bod do spustitelného souboru. Zapíše do konzoly několik instrukčních zpráv a pak deklaruje Task instanci s názvem cancelTask, která bude číst tahy kláves konzoly. Pokud je stisknutá klávesa Enter , provede se volání CancellationTokenSource.Cancel() . Tím se signalizuje zrušení. Dále je proměnná sumPageSizesTask přiřazena z SumPageSizesAsync metody. Oba úkoly se pak předají Task.WhenAny(Task[]), což bude pokračovat po dokončení některého z těchto dvou úkolů.

Další blok kódu zajistí, že se aplikace neukončí, dokud nebude zpracováno zrušení. Pokud je prvním úkolem, který se má dokončit, cancelTask, očekává se sumPageSizeTask. Pokud byla zrušena, při čekání vyvolá System.Threading.Tasks.TaskCanceledException. Blok tuto výjimku zachytí a vytiskne zprávu.

Vytvořte asynchronní metodu pro součet velikostí stránek

Pod metodu Main přidejte metodu SumPageSizesAsync :

static async Task SumPageSizesAsync()
{
    var stopwatch = Stopwatch.StartNew();

    int total = 0;
    foreach (string url in s_urlList)
    {
        int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
        total += contentLength;
    }

    stopwatch.Stop();

    Console.WriteLine($"\nTotal bytes returned:  {total:#,#}");
    Console.WriteLine($"Elapsed time:          {stopwatch.Elapsed}\n");
}

Metoda začíná vytvořením instance a spuštěním Stopwatch. Pak prochází každou adresu URL ve s_urlList a volá ProcessUrlAsync. Při každé iteraci se předá s_cts.Token do ProcessUrlAsync metody a kód vrátí Task<TResult>hodnotu , kde TResult je celé číslo:

int total = 0;
foreach (string url in s_urlList)
{
    int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
    total += contentLength;
}

Přidání metody procesu

Přidejte následující ProcessUrlAsync metodu pod metodu SumPageSizesAsync:

static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
{
    HttpResponseMessage response = await client.GetAsync(url, token);
    byte[] content = await response.Content.ReadAsByteArrayAsync(token);
    Console.WriteLine($"{url,-60} {content.Length,10:#,#}");

    return content.Length;
}

Pro každou danou adresu URL metoda použije client instanci poskytnutou k získání odpovědi jako byte[]. Instance CancellationToken se předává do HttpClient.GetAsync(String, CancellationToken) metod a HttpContent.ReadAsByteArrayAsync() metod. Používá se token k registraci pro požadované zrušení. Délka se vrátí poté, co se adresa URL a délka zapíší do konzoly.

Příklad výstupu aplikace

Application started.
Press the ENTER key to cancel...

https://learn.microsoft.com                                       37,357
https://learn.microsoft.com/aspnet/core                           85,589
https://learn.microsoft.com/azure                                398,939
https://learn.microsoft.com/azure/devops                          73,663
https://learn.microsoft.com/dotnet                                67,452
https://learn.microsoft.com/dynamics365                           48,582
https://learn.microsoft.com/education                             22,924

ENTER key pressed: cancelling downloads.

Application ending.

Kompletní příklad

Následující kód je úplný text souboru Program.cs příkladu.

using System.Diagnostics;

class Program
{
    static readonly CancellationTokenSource s_cts = new CancellationTokenSource();

    static readonly HttpClient s_client = new HttpClient
    {
        MaxResponseContentBufferSize = 1_000_000
    };

    static readonly IEnumerable<string> s_urlList = new string[]
    {
            "https://learn.microsoft.com",
            "https://learn.microsoft.com/aspnet/core",
            "https://learn.microsoft.com/azure",
            "https://learn.microsoft.com/azure/devops",
            "https://learn.microsoft.com/dotnet",
            "https://learn.microsoft.com/dynamics365",
            "https://learn.microsoft.com/education",
            "https://learn.microsoft.com/enterprise-mobility-security",
            "https://learn.microsoft.com/gaming",
            "https://learn.microsoft.com/graph",
            "https://learn.microsoft.com/microsoft-365",
            "https://learn.microsoft.com/office",
            "https://learn.microsoft.com/powershell",
            "https://learn.microsoft.com/sql",
            "https://learn.microsoft.com/surface",
            "https://learn.microsoft.com/system-center",
            "https://learn.microsoft.com/visualstudio",
            "https://learn.microsoft.com/windows",
            "https://learn.microsoft.com/maui"
    };

    static async Task Main()
    {
        Console.WriteLine("Application started.");
        Console.WriteLine("Press the ENTER key to cancel...\n");

        Task cancelTask = Task.Run(() =>
        {
            while (Console.ReadKey().Key != ConsoleKey.Enter)
            {
                Console.WriteLine("Press the ENTER key to cancel...");
            }

            Console.WriteLine("\nENTER key pressed: cancelling downloads.\n");
            s_cts.Cancel();
        });

        Task sumPageSizesTask = SumPageSizesAsync();

        Task finishedTask = await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
        if (finishedTask == cancelTask)
        {
            // wait for the cancellation to take place:
            try
            {
                await sumPageSizesTask;
                Console.WriteLine("Download task completed before cancel request was processed.");
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Download task has been cancelled.");
            }
        }

        Console.WriteLine("Application ending.");
    }

    static async Task SumPageSizesAsync()
    {
        var stopwatch = Stopwatch.StartNew();

        int total = 0;
        foreach (string url in s_urlList)
        {
            int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
            total += contentLength;
        }

        stopwatch.Stop();

        Console.WriteLine($"\nTotal bytes returned:  {total:#,#}");
        Console.WriteLine($"Elapsed time:          {stopwatch.Elapsed}\n");
    }

    static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
    {
        HttpResponseMessage response = await client.GetAsync(url, token);
        byte[] content = await response.Content.ReadAsByteArrayAsync(token);
        Console.WriteLine($"{url,-60} {content.Length,10:#,#}");

        return content.Length;
    }
}

Viz také

Další kroky