Cancelar uma lista de tarefas (C#)Cancel a list of tasks (C#)
Você pode cancelar um aplicativo de console assíncrono se não quiser esperar que ele seja concluído.You can cancel an async console application if you don't want to wait for it to finish. Seguindo o exemplo neste tópico, você pode adicionar um cancelamento a um aplicativo que baixa o conteúdo de uma lista de sites.By following the example in this topic, you can add a cancellation to an application that downloads the contents of a list of websites. Você pode cancelar várias tarefas associando a CancellationTokenSource instância a cada tarefa.You can cancel many tasks by associating the CancellationTokenSource instance with each task. Se você selecionar a tecla Enter , cancelará todas as tarefas que ainda não foram concluídas.If you select the Enter key, you cancel all tasks that aren't yet complete.
Este tutorial abrange:This tutorial covers:
- Criando um aplicativo de console .NETCreating a .NET console application
- Escrevendo um aplicativo assíncrono que dá suporte ao cancelamentoWriting an async application that supports cancellation
- Demonstrando o cancelamento de sinalizaçãoDemonstrating signaling cancellation
Pré-requisitosPrerequisites
Este tutorial exige o seguinte:This tutorial requires the following:
- SDK do .NET 5,0 ou posterior.NET 5.0 or later SDK
- IDE (ambiente de desenvolvimento integrado)Integrated development environment (IDE)
Criar aplicativo de exemploCreate example application
Crie um novo aplicativo de console .NET Core.Create a new .NET Core console application. Você pode criar um usando o dotnet new console
comando ou do Visual Studio.You can create one by using the dotnet new console
command or from Visual Studio. Abra o arquivo Program.cs em seu editor de código favorito.Open the Program.cs file in your favorite code editor.
Substituir usando instruçõesReplace using statements
Substitua as instruções using existentes por estas declarações:Replace the existing using statements with these declarations:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
Adicionar camposAdd fields
Na Program
definição de classe, adicione estes três campos:In the Program
class definition, add these three fields:
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://docs.microsoft.com",
"https://docs.microsoft.com/aspnet/core",
"https://docs.microsoft.com/azure",
"https://docs.microsoft.com/azure/devops",
"https://docs.microsoft.com/dotnet",
"https://docs.microsoft.com/dynamics365",
"https://docs.microsoft.com/education",
"https://docs.microsoft.com/enterprise-mobility-security",
"https://docs.microsoft.com/gaming",
"https://docs.microsoft.com/graph",
"https://docs.microsoft.com/microsoft-365",
"https://docs.microsoft.com/office",
"https://docs.microsoft.com/powershell",
"https://docs.microsoft.com/sql",
"https://docs.microsoft.com/surface",
"https://docs.microsoft.com/system-center",
"https://docs.microsoft.com/visualstudio",
"https://docs.microsoft.com/windows",
"https://docs.microsoft.com/xamarin"
};
O CancellationTokenSource é usado para sinalizar um cancelamento solicitado para um CancellationToken .The CancellationTokenSource is used to signal a requested cancellation to a CancellationToken. O HttpClient
expõe a capacidade de enviar solicitações HTTP e receber respostas http.The HttpClient
exposes the ability to send HTTP requests and receive HTTP responses. O s_urlList
mantém todas as URLs que o aplicativo planeja processar.The s_urlList
holds all of the URLs that the application plans to process.
Atualizar ponto de entrada do aplicativoUpdate application entry point
O ponto de entrada principal no aplicativo de console é o Main
método.The main entry point into the console application is the Main
method. Substitua o método existente pelo seguinte:Replace the existing method with the following:
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();
await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
Console.WriteLine("Application ending.");
}
O Main
método atualizado agora é considerado um Async Main, que permite um ponto de entrada assíncrono no executável.The updated Main
method is now considered an Async main, which allows for an asynchronous entry point into the executable. Ele grava algumas mensagens instrutivas no console e, em seguida, declara uma Task instância chamada cancelTask
, que lerá os traços de tecla do console.It writes a few instructional messages to the console, then declares a Task instance named cancelTask
, which will read console key strokes. Se a tecla Enter for pressionada, será feita uma chamada para CancellationTokenSource.Cancel() .If the Enter key is pressed, a call to CancellationTokenSource.Cancel() is made. Isso sinalizará o cancelamento.This will signal cancellation. Em seguida, a sumPageSizesTask
variável é atribuída a partir do SumPageSizesAsync
método.Next, the sumPageSizesTask
variable is assigned from the SumPageSizesAsync
method. Em seguida, as duas tarefas são passadas para Task.WhenAny(Task[]) o, o que continuará quando qualquer uma das duas tarefas for concluída.Both tasks are then passed to Task.WhenAny(Task[]), which will continue when any of the two tasks have completed.
Criar o método de tamanhos de página de soma assíncronaCreate the asynchronous sum page sizes method
Abaixo do Main
método, adicione o SumPageSizesAsync
método:Below the Main
method, add the SumPageSizesAsync
method:
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");
}
O método começa instanciando e iniciando um Stopwatch .The method starts by instantiating and starting a Stopwatch. Em seguida, ele executa um loop em cada URL nas s_urlList
chamadas e ProcessUrlAsync
.It then loops through each URL in the s_urlList
and calls ProcessUrlAsync
. Com cada iteração, o s_cts.Token
é passado para o ProcessUrlAsync
método e o código retorna um Task<TResult> , em que TResult
é um inteiro:With each iteration, the s_cts.Token
is passed into the ProcessUrlAsync
method and the code returns a Task<TResult>, where TResult
is an integer:
int total = 0;
foreach (string url in s_urlList)
{
int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
total += contentLength;
}
Adicionar método de processoAdd process method
Adicione o seguinte ProcessUrlAsync
método abaixo do SumPageSizesAsync
método:Add the following ProcessUrlAsync
method below the SumPageSizesAsync
method:
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;
}
Para qualquer URL fornecida, o método usará a client
instância fornecida para obter a resposta como um byte[]
.For any given URL, the method will use the client
instance provided to get the response as a byte[]
. A CancellationToken instância é passada para os HttpClient.GetAsync(String, CancellationToken) HttpContent.ReadAsByteArrayAsync() métodos e.The CancellationToken instance is passed into the HttpClient.GetAsync(String, CancellationToken) and HttpContent.ReadAsByteArrayAsync() methods. O token
é usado para se registrar para o cancelamento solicitado.The token
is used to register for requested cancellation. O comprimento é retornado depois que a URL e o comprimento são gravados no console.The length is returned after the URL and length is written to the console.
Exemplo de saída de aplicativoExample application output
Application started.
Press the ENTER key to cancel...
https://docs.microsoft.com 37,357
https://docs.microsoft.com/aspnet/core 85,589
https://docs.microsoft.com/azure 398,939
https://docs.microsoft.com/azure/devops 73,663
https://docs.microsoft.com/dotnet 67,452
https://docs.microsoft.com/dynamics365 48,582
https://docs.microsoft.com/education 22,924
ENTER key pressed: cancelling downloads.
Application ending.
Exemplo completoComplete example
O código a seguir é o texto completo do arquivo Program.cs para o exemplo.The following code is the complete text of the Program.cs file for the example.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
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://docs.microsoft.com",
"https://docs.microsoft.com/aspnet/core",
"https://docs.microsoft.com/azure",
"https://docs.microsoft.com/azure/devops",
"https://docs.microsoft.com/dotnet",
"https://docs.microsoft.com/dynamics365",
"https://docs.microsoft.com/education",
"https://docs.microsoft.com/enterprise-mobility-security",
"https://docs.microsoft.com/gaming",
"https://docs.microsoft.com/graph",
"https://docs.microsoft.com/microsoft-365",
"https://docs.microsoft.com/office",
"https://docs.microsoft.com/powershell",
"https://docs.microsoft.com/sql",
"https://docs.microsoft.com/surface",
"https://docs.microsoft.com/system-center",
"https://docs.microsoft.com/visualstudio",
"https://docs.microsoft.com/windows",
"https://docs.microsoft.com/xamarin"
};
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();
await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
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;
}
}
Consulte tambémSee also
- CancellationToken
- CancellationTokenSource
- Programação assíncrona com async e await (C#)Asynchronous programming with async and await (C#)