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í:
- .NET 5 nebo novější sada SDK
- Integrované vývojové prostředí (IDE)
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 cancelTask
první ú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 ProcessUrlAsync
a 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;
}
}