Tarefa C#

Resumo : neste tutorial, você aprenderá sobre o padrão assíncrono baseado em tarefas (TAP) em C# e como usar a classe C# Task para criar operações assíncronas.

Introdução ao padrão assíncrono baseado em tarefas (TAP)

C# introduziu um modelo de programação assíncrona (APM) que fornece uma maneira de executar operações vinculadas de E/S de forma assíncrona.

O APM é baseado em conceitos de retorno de chamada:

  • Um método que representa uma operação assíncrona que aceita um retorno de chamada.
  • Quando a operação assíncrona for concluída, o método invocará o retorno de chamada para notificar o código de chamada.

Como o APM é bastante difícil de entender, o C# introduziu o padrão assíncrono baseado em eventos (EAP) que executa operações assíncronas usando eventos.

Ao contrário do APM, no EAP, o método gera um evento quando a operação assíncrona é concluída, em vez de chamar um retorno de chamada.

O EAP é mais fácil de usar e tem melhor tratamento de erros do que o APM. No entanto, o EAP é bastante complexo de usar.

Para resolver esse problema, o C# introduziu a programação assíncrona baseada em tarefas (TAP), que simplifica bastante a programação assíncrona e facilita a gravação de código assíncrono.

O TAP consiste nos seguintes componentes principais:

  • A Taskclasse – representa uma operação assíncrona.
  • As palavras-chave async/ await– definem métodos assíncronos e aguardam a conclusão das operações assíncronas.
  • API baseada em tarefas – um conjunto de classes que funcionam perfeitamente com a classe Task e palavras-chave async/await.

A TAP tem as seguintes vantagens:

  • Desempenho aprimorado – O TAP pode melhorar o desempenho de um aplicativo, permitindo que ele execute operações vinculadas a E/S de forma assíncrona, liberando a CPU para outras tarefas.
  • Código simplificado – TAP permite escrever código assíncrono como código síncrono, o que facilita a compreensão.
  • Melhor gerenciamento de recursos – O TAP otimiza os recursos do sistema, permitindo que os aplicativos executem operações assíncronas sem bloquear threads.

Neste tutorial, focaremos na Taskclasse e em como usá-la para executar operações assíncronas.

A classe Tarefa

A Taskaula é um conceito central da TAP. Representa uma operação assíncrona que pode ser executada de várias maneiras.

Suponha que você tenha um método que executa uma operação assíncrona chamada GetRandomNumber()que retorna um número aleatório entre 1 e 100 assim:

static int GetRandomNumber()
{
    Thread.Sleep(1000);
    int randomNumber = (new Random()).Next(1, 100);
    Console.WriteLine($"The random number is {randomNumber}");
    return randomNumber;
}Linguagem de código:  C#  ( cs )

Ao contrário de uma função regular, GetRandomNumber()usa o Thread.Sleep()para atrasar um segundo antes de retornar um número aleatório. O objetivo Thread.Sleep()é simular uma operação assíncrona que leva cerca de um segundo para ser concluída.

Executando uma tarefa

Para executar o GetRandomNumber()método de forma assíncrona, você cria um novo Taskobjeto e chama o GetRandomNumber()método em uma expressão lambda passada ao Taskconstrutor do:

var task = new Task(() => GetRandomNumber());Linguagem de código:  C#  ( cs )

e comece a executar a tarefa chamando o Start()método do Taskobjeto:

task.Start();Linguagem de código:  C#  ( cs )

Junte tudo:

static int GetRandomNumber()
{
    Thread.Sleep(1000);
    int randomNumber = (new Random()).Next(1, 100);
    Console.WriteLine($"The random number is {randomNumber}");
    return randomNumber;
}

var task = new Task(() => GetRandomNumber());
task.Start();

Console.WriteLine("Start the program...");

Console.ReadLine();Linguagem de código:  C#  ( cs )

Saída:

Start the program...
The random number is 65Linguagem de código:  C#  ( cs )

Observe que o task.Start()método não bloqueia o thread principal, portanto você verá a seguinte mensagem primeiro:

Start the program...Linguagem de código:  C#  ( cs )

….antes do número aleatório:

The random number is 65Linguagem de código:  C#  ( cs )

O Console.ReadLine()bloqueia o thread principal até que você pressione uma tecla. É usado para aguardar a Taskconclusão do thread filho agendado pelo objeto.

Se você não bloquear o thread principal, ele será encerrado após o programa exibir a mensagem “Inicie o programa…”.

Observe que o Taskconstrutor aceita muitas outras opções com as quais você não precisa se preocupar por enquanto.

Nos bastidores, o programa usa um pool de threads para executar a operação assíncrona. O Start()método agenda a operação para execução.

Para provar isso, podemos exibir o ID do thread e se o thread pertence ou não ao pool de threads gerenciado:

static int GetRandomNumber()
{
    var threadId = Thread.CurrentThread.ManagedThreadId;
    var threadPool = Thread.CurrentThread.IsThreadPoolThread;

    Console.WriteLine($"The thread #{threadId}, use a thread pool {threadPool}");

    Thread.Sleep(1000);
    int randomNumber = (new Random()).Next(1, 100);
    Console.WriteLine($"The random number is {randomNumber}");
    return randomNumber;
}

var task = new Task(() => GetRandomNumber());
task.Start();

Console.WriteLine("Start the program...");

Console.ReadLine();Linguagem de código:  JavaScript  ( javascript )

Saída:

Start the program...
The thread #5, use a thread pool True
The random number is 97Linguagem de código:  PHP  ( php )

A saída mostra que o ID do thread é 5 e o thread pertence a um conjunto de threads. Observe que você provavelmente verá um número diferente.

Como o código para criar um Taskobjeto e iniciá-lo é bastante detalhado, você pode encurtá-lo usando o Run()método estático da Taskclasse:

Task.Run(() => GetRandomNumber());Linguagem de código:  C#  ( cs )

O Run()método enfileira a operação ( GetRandomNumber) no conjunto de threads para execução.

Da mesma forma, você pode usar o StartNew()método do Factoryobjeto da Taskclasse para criar uma nova tarefa e agendar sua execução:

Task.Factory.StartNew(() => GetRandomNumber());Linguagem de código:  C#  ( cs )

Obtendo o resultado de uma tarefa

O Run()método retorna um objeto Task< TResult> que representa o resultado da operação assíncrona.

Em nosso exemplo, the GetRandomNumber()retorna um número inteiro, portanto, Task.Run()retorna o Task<int>objeto:

Task<int> task = Task.Run(() => GetRandomNumber());Linguagem de código:  C#  ( cs )

Para obter o número retornado do GetRandomNumber()método, você usa a Resultpropriedade do objeto task:

task.ResultLinguagem de código:  C#  ( cs )

Junte tudo.

static int GetRandomNumber()
{
    Thread.Sleep(1000);
    int randomNumber = (new Random()).Next(1, 100);
    return randomNumber;
}


// The main thread is blocked
// until the result is available
Task<int> task = Task.Run(() => GetRandomNumber());

Console.WriteLine($"The random number is {task.Result}"); Linguagem de código:  C#  ( cs )

Saída:

The random number is 15Linguagem de código:  C#  ( cs )

Resumo

  • Use programação assíncrona baseada em tarefas (TAP) para desenvolver programas assíncronos.
  • Use a Taskclasse para executar operações assíncronas.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *