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
  • Zápis asynchronní aplikace, která podporuje zrušení
  • Předvedení signálu o zrušení

Požadavky

V tomto kurzu budete potřebovat následující:

Vytvoření ukázkové aplikace

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

Nahrazení příkazů using

Nahraďte existující příkazy using 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"
};

Slouží CancellationTokenSource k signalizaci požadovaného zrušení CancellationToken. 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á Main metoda je nyní považována za asynchronní hlavní, 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 signalizují 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 neodejde, dokud se zrušení nezpracuje. Pokud je cancelTaskprvní úkol, který se má dokončit, sumPageSizeTask očekává se. Pokud byla zrušena, když se čekalo, že vyvolá .System.Threading.Tasks.TaskCanceledException Blok tuto výjimku zachytí a vytiskne zprávu.

Vytvoření metody asynchronních velikostí stránek součtu

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 voláních ProcessUrlAsynca volá . 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

Pod metodu přidejte následující ProcessUrlAsync 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. Slouží token k registraci k požadovanému zrušení. Délka se vrátí za adresou URL a délkou se zapíše 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 pro příklad.

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