Cancelar tarefas assíncronas após um período (C#)Cancel async tasks after a period of time (C#)

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 aguardar a conclusão da operação.You can cancel an asynchronous operation after a period of time by using the CancellationTokenSource.CancelAfter method if you don't want to wait for the operation to finish. Esse método agenda o cancelamento de todas as tarefas associadas que não são concluídas dentro do período designado pela CancelAfter expressão.This method schedules the cancellation of any associated tasks that aren't complete within the period of time that's designated by the CancelAfter expression.

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.This example adds to the code that's developed in Cancel a list of tasks (C#) to download a list of websites and to display the length of the contents of each one.

Este tutorial abrange:This tutorial covers:

  • Atualizando um aplicativo de console .NET existenteUpdating an existing .NET console application
  • Agendando um cancelamentoScheduling a cancellation

Pré-requisitosPrerequisites

Este tutorial exige o seguinte:This tutorial requires the following:

Atualizar ponto de entrada do aplicativoUpdate application entry point

Substitua o Main método existente pelo seguinte:Replace the existing Main method with the following:

static async Task Main()
{
    Console.WriteLine("Application started.");

    try
    {
        s_cts.CancelAfter(3500);

        await SumPageSizesAsync();
    }
    catch (TaskCanceledException)
    {
        Console.WriteLine("\nTasks cancelled: timed out.\n");
    }
    finally
    {
        s_cts.Dispose();
    }

    Console.WriteLine("Application ending.");
}

O Main método atualizado grava algumas mensagens instrutivas no console do.The updated Main method writes a few instructional messages to the console. Dentro de try catch, uma chamada para CancellationTokenSource.CancelAfter(Int32) agendar um cancelamento.Within the try catch, a call to CancellationTokenSource.CancelAfter(Int32) schedules a cancellation. Isso sinalizará o cancelamento após um período de tempo.This will signal cancellation after a period of time.

Em seguida, o SumPageSizesAsync método é aguardado.Next, the SumPageSizesAsync method is awaited. Se o processamento de todas as URLs ocorrer mais rápido do que o cancelamento agendado, o aplicativo será encerrado.If processing all of the URLs occurs faster than the scheduled cancellation, the application ends. No entanto, se o cancelamento agendado for disparado antes que todas as URLs sejam processadas, um TaskCanceledException será lançado.However, if the scheduled cancellation is triggered before all of the URLs are processed, a TaskCanceledException is thrown.

Exemplo de saída de aplicativoExample application output

Application started.

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

Tasks cancelled: timed out.

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.");

        try
        {
            s_cts.CancelAfter(3500);

            await SumPageSizesAsync();
        }
        catch (TaskCanceledException)
        {
            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;
    }
}

Consulte tambémSee also