Cancelar tarefas assíncronas após um período
Você pode cancelar uma operação assíncrona após um período usando o método CancellationTokenSource.CancelAfter se não quiser aguardar a conclusão da operação. Esse método agenda o cancelamento de quaisquer tarefas associadas que não são concluídas dentro do período designado pela expressão CancelAfter
.
Este exemplo adiciona o código desenvolvido em Cancelar uma tarefa assíncrona ou uma lista de tarefas (C#) para baixar uma lista de sites e para exibir o tamanho dos conteúdos de cada um.
Este tutorial abrange:
- Atualizando um aplicativo de console .NET existente
- Agendando um cancelamento
Pré-requisitos
Este tutorial exige o seguinte:
- Espera-se que você tenha criado um aplicativo no tutorial Cancelar uma lista de tarefas (C#)
- .NET 5 ou SDK posterior
- IDE (ambiente de desenvolvimento integrado)
Atualize o ponto de entrada do aplicativo.
Substitua o método Main
existente 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 Main
atualizado grava algumas mensagens instrutivas no console. Dentro do try-catch
, uma chamada para CancellationTokenSource.CancelAfter(Int32) agenda um cancelamento. Isso sinalizará o cancelamento após um período.
Em seguida, o método SumPageSizesAsync
é aguardado. Se o processamento de todas as URLs ocorrer mais rápido do que o cancelamento agendado, o aplicativo é encerrado. No entanto, se o cancelamento agendado for disparado antes que todas as URLs sejam processadas, um OperationCanceledException será gerado.
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;
}
}