C# - Cancelamento de operações assíncronas - II


Hoje vamos continuar mostrando como cancelar operações assíncronas na linguagem C#.

Continuando o artigo anterior veremos agora como definir um período de tempo após o qual a operação será cancelada.

Podemos realizar o cancelamento de operações assíncronas definindo um período de tempo após o qual a operação deve ser cancelada usando duas abordagens básicas:

  1. Usar o construtor da classe CancellationTokenSource(int  valor) ou CancellationTokenSource(TimeSpan valor) onde podemos definir um valor em milissegundos ou um timespan após o qual a operação será cancelada;
     
  2. Usar o método CancelAfter(int valor) ou CancelAfter(TimeSpan valor) onde valor é o período de espera antes de cancelar o CancellationTokenSource;

Vejamos um exemplo da primeira abordagem.

Cancelando uma operação usando CancellationTokenSource(int)

Vamos continuar usando a tarefa de longa duração que definimos no artigo anterior e que estou mostrando abaixo>

 private static Task<int> OperacaoLongaDuracaoCancelavel(int valor, 
            CancellationToken cancellationToken = default)
        {
            Console.WriteLine("Executou Operação de longa duração");
            Task<int> task = null;
            task = Task.Run(() =>
            {
                int resultado = 0;
                for (int i = 0; i < valor; i++)
                {
                    if (cancellationToken.IsCancellationRequested)
                        throw new TaskCanceledException(task);
                    Thread.Sleep(50);
                    resultado += i;
                }
                return resultado;
            });
            return task;
        }

Agora vamos criar o método ExecutaCancelamentoComTimeout(int tempo) que vai receber o valor do período de tempo que desejamos gastar antes de executar a operação.

A seguir no método estamos criando uma instância de CancellationTokenSource para notificar a operação do cancelamento após o período de tempo ser transcorrido.

A chamada do método e longa duração continua sendo feito da mesma forma:

       public static async Task ExecutaCancelamentoComTimeout(int tempo)
        {
            using (var cancellationTokenSource = new CancellationTokenSource(tempo))
            {
                try
                {
                    var resultado = await OperacaoLongaDuracaoCancelavel(100, 
                        cancellationTokenSource.Token);
                    Console.WriteLine($"Resultado {resultado}");
                }
                catch (TaskCanceledException)
                {
                    throw;
                }
            }
        }

No método Main() podemos invocar o método ExecutaCancelamentoComTimeout(int tempo) para cancelar a tarefa passando o tempo de delay que queremos usar:

        static async Task Main(string[] args)
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            try
            {
                await ExecutaCancelamentoComTimeout(2500);
            }
            catch (Exception)
            {
                Console.WriteLine($"Tarefa cancelada: " +
               $"tempo expirado após {stopwatch.Elapsed }.\n");
            }
            Console.ReadKey();
        }

 

Executando o projeto teremos o resultado abaixo:

Vejamos agora a outra abordagem.

Cancelando uma operação usando o métodc CancelAfter(int)

Aqui basta usar o mesmo método definido acima e usar o método CancelAfter() passando o tempo desejado:

       public static async Task ExecutaCancelamentoComTimeout(int tempo)
        {
            using (var cancellationTokenSource = new CancellationTokenSource())
            {
                cancellationTokenSource.CancelAfter(tempo);
                try
                {
                    var resultado = await OperacaoLongaDuracaoCancelavel(100, 
                        cancellationTokenSource.Token);
                    Console.WriteLine($"Resultado {resultado}");
                }
                catch (TaskCanceledException)
                {
                    throw;
                }
            }
        }

 

A chamada é feita da mesma forma e o resultado obtido será o mesmo.

Na próxima parte do artigo veremos como cancelar uma operação assíncrona manualmente.

Pegue o projeto aqui:   CShp_TaskCancel.zip

(Disse Jesus) "E, se o teu olho te escandalizar, lança-o fora; melhor é para ti entrares no reino de Deus com um só olho do que, tendo dois olhos, seres lançado no fogo do inferno, Onde o seu bicho não morre, e o fogo nunca se apaga."
Marcos 9:47,48

Referências:


José Carlos Macoratti