Avbryt en lista över uppgifter
Du kan avbryta ett asynkront konsolprogram om du inte vill vänta tills det har slutförts. Genom att följa exemplet i det här avsnittet kan du lägga till en annullering till ett program som laddar ned innehållet i en lista över webbplatser. Du kan avbryta många aktiviteter genom att associera instansen CancellationTokenSource med varje uppgift. Om du väljer returnyckeln avbryter du alla aktiviteter som ännu inte har slutförts.
Den här självstudiekursen omfattar:
- Skapa ett .NET-konsolprogram
- Skriva ett asynkront program som stöder annullering
- Demonstrerar avbokning av signaler
Förutsättningar
För den här kursen behöver du följande:
- .NET 5 eller senare SDK
- Integrerad utvecklingsmiljö (IDE)
Skapa exempelprogram
Skapa ett nytt .NET Core-konsolprogram. Du kan skapa en med hjälp dotnet new console
av kommandot eller från Visual Studio. Öppna filen Program.cs i din favoritkodredigerare.
Ersätt med -instruktioner
Ersätt de befintliga användningssatserna med följande deklarationer:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Lägg till fält
Lägg till följande tre fält i klassdefinitionen 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://video2.skills-academy.com",
"https://video2.skills-academy.com/aspnet/core",
"https://video2.skills-academy.com/azure",
"https://video2.skills-academy.com/azure/devops",
"https://video2.skills-academy.com/dotnet",
"https://video2.skills-academy.com/dynamics365",
"https://video2.skills-academy.com/education",
"https://video2.skills-academy.com/enterprise-mobility-security",
"https://video2.skills-academy.com/gaming",
"https://video2.skills-academy.com/graph",
"https://video2.skills-academy.com/microsoft-365",
"https://video2.skills-academy.com/office",
"https://video2.skills-academy.com/powershell",
"https://video2.skills-academy.com/sql",
"https://video2.skills-academy.com/surface",
"https://video2.skills-academy.com/system-center",
"https://video2.skills-academy.com/visualstudio",
"https://video2.skills-academy.com/windows",
"https://video2.skills-academy.com/maui"
};
CancellationTokenSource Används för att signalera en begärd annullering till en CancellationToken. Gör HttpClient
det möjligt att skicka HTTP-begäranden och ta emot HTTP-svar. Innehåller s_urlList
alla URL:er som programmet planerar att bearbeta.
Uppdatera programmets startpunkt
Den viktigaste startpunkten i konsolprogrammet är Main
metoden. Ersätt den befintliga metoden med följande:
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.");
}
Den uppdaterade Main
metoden betraktas nu som en Async-huvud, vilket möjliggör en asynkron startpunkt i den körbara filen. Den skriver några instruktionsmeddelanden till konsolen och deklarerar sedan en Task instans med namnet cancelTask
, som läser konsolnyckelstreck. Om Retur-tangenten trycks på görs ett anrop tillCancellationTokenSource.Cancel(). Detta kommer att signalera annullering. Sedan tilldelas variabeln sumPageSizesTask
från SumPageSizesAsync
-metoden. Båda aktiviteterna skickas sedan till Task.WhenAny(Task[]), som fortsätter när någon av de två uppgifterna har slutförts.
Nästa kodblock ser till att programmet inte avslutas förrän annulleringen har bearbetats. Om den första uppgiften som ska slutföras är cancelTask
sumPageSizeTask
väntar den. Om den avbröts när den väntades kastar den en System.Threading.Tasks.TaskCanceledException. Blocket fångar det undantaget och skriver ut ett meddelande.
Skapa metoden för asynkrona sum-sidstorlekar
Main
Lägg till SumPageSizesAsync
metoden under metoden:
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");
}
Metoden börjar med att instansiera och starta en Stopwatch. Den loopar sedan igenom varje URL i s_urlList
och anropar ProcessUrlAsync
. För varje iteration s_cts.Token
skickas metoden till ProcessUrlAsync
och koden returnerar ett Task<TResult>, där TResult
är ett heltal:
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
Lägg till processmetod
Lägg till följande ProcessUrlAsync
metod under SumPageSizesAsync
metoden:
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;
}
För en viss URL använder metoden den angivna instansen client
för att hämta svaret som en byte[]
. Instansen CancellationTokenHttpClient.GetAsync(String, CancellationToken) skickas till metoderna och HttpContent.ReadAsByteArrayAsync() . token
Används för att registrera för begärd annullering. Längden returneras när URL:en och längden har skrivits till konsolen.
Exempel på programutdata
Application started.
Press the ENTER key to cancel...
https://video2.skills-academy.com 37,357
https://video2.skills-academy.com/aspnet/core 85,589
https://video2.skills-academy.com/azure 398,939
https://video2.skills-academy.com/azure/devops 73,663
https://video2.skills-academy.com/dotnet 67,452
https://video2.skills-academy.com/dynamics365 48,582
https://video2.skills-academy.com/education 22,924
ENTER key pressed: cancelling downloads.
Application ending.
Fullständigt exempel
Följande kod är den fullständiga texten i Filen Program.cs för exemplet.
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://video2.skills-academy.com",
"https://video2.skills-academy.com/aspnet/core",
"https://video2.skills-academy.com/azure",
"https://video2.skills-academy.com/azure/devops",
"https://video2.skills-academy.com/dotnet",
"https://video2.skills-academy.com/dynamics365",
"https://video2.skills-academy.com/education",
"https://video2.skills-academy.com/enterprise-mobility-security",
"https://video2.skills-academy.com/gaming",
"https://video2.skills-academy.com/graph",
"https://video2.skills-academy.com/microsoft-365",
"https://video2.skills-academy.com/office",
"https://video2.skills-academy.com/powershell",
"https://video2.skills-academy.com/sql",
"https://video2.skills-academy.com/surface",
"https://video2.skills-academy.com/system-center",
"https://video2.skills-academy.com/visualstudio",
"https://video2.skills-academy.com/windows",
"https://video2.skills-academy.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;
}
}