Cancelar tarefas assíncronas após um período de tempo
Você pode cancelar uma operação assíncrona após um período de tempo usando o CancellationTokenSource.CancelAfter método se não quiser esperar que a operação seja concluída. Este método agenda o cancelamento de quaisquer tarefas associadas que não sejam concluídas dentro do período de tempo designado pela CancelAfter
expressão.
Este exemplo adiciona ao código desenvolvido em Cancelar uma lista de tarefas (C#) para baixar uma lista de sites e exibir o comprimento do conteúdo de cada um.
Este tutorial aborda:
- Atualizando um aplicativo de console .NET existente
- Agendar um cancelamento
Pré-requisitos
Neste tutorial necessita do seguinte:
- Espera-se que você tenha criado um aplicativo no tutorial Cancelar uma lista de tarefas (C#)
- SDK do .NET 5 ou posterior
- Ambiente de desenvolvimento integrado (IDE)
Atualizar o ponto de entrada do aplicativo
Substitua o método existente Main
pelo seguinte:
static async Task Main()
{
Console.WriteLine("Application started.");
try
{
s_cts.CancelAfter(3500);
await SumPageSizesAsync();
}
catch (OperationCanceledException)
{
Console.WriteLine("\nTasks cancelled: timed out.\n");
}
finally
{
s_cts.Dispose();
}
Console.WriteLine("Application ending.");
}
O método atualizado Main
grava algumas mensagens de instrução no console. Dentro do try-catch
, uma chamada para CancellationTokenSource.CancelAfter(Int32) agendar um cancelamento. Isso sinalizará o cancelamento após um período de tempo.
Em seguida, o SumPageSizesAsync
método é aguardado. Se o processamento de todos os URLs ocorrer mais rápido do que o cancelamento agendado, o aplicativo será encerrado. No entanto, se o cancelamento agendado for acionado antes que todos os URLs sejam processados, um OperationCanceledException será lançado.
Exemplo de saída de aplicativo
Application started.
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
Tasks cancelled: timed out.
Application ending.
Exemplo completo
O código a seguir é o texto completo do arquivo Program.cs para o exemplo.
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.");
try
{
s_cts.CancelAfter(3500);
await SumPageSizesAsync();
}
catch (OperationCanceledException)
{
Console.WriteLine("\nTasks cancelled: timed out.\n");
}
finally
{
s_cts.Dispose();
}
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;
}
}