Anulowanie listy zadań
Jeśli nie chcesz czekać na zakończenie, możesz anulować aplikację konsolową asynchronicznych. Korzystając z przykładu w tym temacie, możesz dodać anulowanie do aplikacji, która pobiera zawartość listy witryn internetowych. Wiele zadań można anulować, kojarząc CancellationTokenSource wystąpienie z każdym zadaniem. Jeśli wybierzesz klawisz Enter , anulujesz wszystkie zadania, które nie zostały jeszcze ukończone.
W tym samouczku opisano następujące czynności:
- Tworzenie aplikacji konsolowej platformy .NET
- Pisanie aplikacji asynchronicznych obsługującej anulowanie
- Demonstrowanie anulowania sygnału
Wymagania wstępne
Dla tego samouczka wymagane są następujące elementy:
- Zestaw SDK platformy .NET 5 lub nowszej
- Zintegrowane środowisko projektowe (IDE)
Tworzenie przykładowej aplikacji
Utwórz nową aplikację konsolową platformy .NET Core. Możesz go utworzyć przy użyciu dotnet new console
polecenia lub programu Visual Studio. Otwórz plik Program.cs w ulubionym edytorze kodu.
Zastępowanie instrukcji using
Zastąp istniejące instrukcje using następującymi deklaracjami:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Dodaj pola
Program
W definicji klasy dodaj następujące trzy pola:
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"
};
Element CancellationTokenSource służy do sygnalizowania żądanego anulowania do .CancellationToken Funkcja HttpClient
uwidacznia możliwość wysyłania żądań HTTP i odbierania odpowiedzi HTTP. Zawiera s_urlList
wszystkie adresy URL, które aplikacja planuje przetworzyć.
Aktualizowanie punktu wejścia aplikacji
Głównym punktem wejścia do aplikacji konsolowej jest Main
metoda . Zastąp istniejącą metodę następującym kodem:
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.");
}
Zaktualizowana Main
metoda jest teraz traktowana jako główna asynchroniczna, która umożliwia asynchroniczny punkt wejścia do pliku wykonywalnego. Zapisuje kilka komunikatów instruktażowych w konsoli, a następnie deklaruje wystąpienie o nazwie cancelTask
, które odczytuje Task pociągnięcia klucza konsoli. Jeśli klawisz Enter zostanie naciśnięty, zostanie wykonane wywołanie CancellationTokenSource.Cancel() metody . Spowoduje to anulowanie. Następnie zmienna sumPageSizesTask
jest przypisywana SumPageSizesAsync
z metody . Oba zadania są następnie przekazywane do Task.WhenAny(Task[])elementu , co będzie kontynuowane po zakończeniu któregokolwiek z dwóch zadań.
Następny blok kodu gwarantuje, że aplikacja nie zostanie zakończona, dopóki anulowanie nie zostanie przetworzone. Jeśli pierwszym zadaniem do ukończenia cancelTask
jest , oczekiwany jest element sumPageSizeTask
. Jeśli została anulowana, gdy oczekiwano, zgłasza wartość System.Threading.Tasks.TaskCanceledException. Blok przechwytuje ten wyjątek i wyświetla komunikat.
Tworzenie metody asynchronicznej sumowania rozmiarów stron
Main
Poniżej metody dodaj metodę 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 rozpoczyna się od utworzenia wystąpienia i uruchomienia klasy Stopwatch. Następnie przechodzi przez każdy adres URL w s_urlList
pętli i wywołuje metodę ProcessUrlAsync
. W przypadku każdej iteracji element s_cts.Token
jest przekazywany do ProcessUrlAsync
metody , a kod zwraca Task<TResult>wartość , gdzie TResult
jest liczbą całkowitą:
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
Dodawanie metody procesu
Dodaj następującą ProcessUrlAsync
metodę SumPageSizesAsync
poniżej metody:
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;
}
W przypadku dowolnego adresu URL metoda użyje podanego client
wystąpienia, aby uzyskać odpowiedź jako byte[]
. Wystąpienie CancellationToken jest przekazywane do HttpClient.GetAsync(String, CancellationToken) metod i HttpContent.ReadAsByteArrayAsync() . Element token
służy do rejestrowania się w celu zażądanego anulowania. Długość jest zwracana po zapisaniu adresu URL i długości do konsoli.
Przykładowe dane wyjściowe aplikacji
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.
Kompletny przykład
Poniższy kod jest kompletnym tekstem pliku Program.cs w tym przykładzie.
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;
}
}
Zobacz też
- CancellationToken
- CancellationTokenSource
- Programowanie asynchroniczne z funkcją asynchroniczną i await (C#)