C# - Programação Assíncrona como : Async e Task


 Neste artigo vou revisar os conceitos da programação assíncrona na linguagem C#.

A programação assíncrona é um poderoso recurso da linguagem C# que permite que você continue com a execução do seu programa na thread principal enquanto uma tarefa de longa duração é executada na sua própria thread separadamente da thread principal.

Quando a tarefa de longa duração estiver completa, ela permitirá que a thread principal saiba se tarefa foi concluída com sucesso ou se a operação falhou.

Os tipos de retorno dos métodos/funções assíncronos

Na programação assíncrona, os métodos assíncronos podem ter três tipos possíveis de retorno :

Vamos então criar um exemplo onde iremos usar esses tipos de retorno.

Recursos Usados:

Programação Assíncrona com retorno void

Abra o VS 2017 Community e crie uma solução em branco usando o template: Other Project Types -> Visual Studio Solutions;

Escolha Blank Solution e informe o nome Net_ProgAsync e clique em OK;

A seguir no menu File clique em Add -> New Project e escolha Visual C# -> Windows Classic Desktop -> Class Library (.NET Framework);

Informe o nome Net_ProgAsync.CLDemo e clique em OK;

O projeto Class Library vai criar uma classe Class1.cs no projeto altere o nome dessa classe para Exemplo.cs.

Após isso inclua outro projeto na solução via opção File-> Add -> New Project e escolha Windows Forms App (.NET Framework);

Informe o nome Net_ProgAsync.WF e clique em OK.

Ao final teremos uma solução contendo dois projetos conforme mostra a figura abaixo:

Projeto Windows Forms : Referenciando o projeto Class Library

Vamos incluir uma referência no projeto Windows Forms ao projeto Class Library.

Na janela Solution Explorer clique com o botão direito sobre o projeto Windows Forms (Net_ProgAsync.WF) e a seguir clique em Add -> Reference;

Clique na guia Projects e marque o projeto Net_ProgAsync.CLDemo e clique em OK;



Para não esquecer vamos definir o projeto Windows Forms como o projeto a ser executado. Clique com o botão direito sobre o projeto e a seguir clique em : Set As Startup Project.

Abra o formulário Form1.cs do projeto e inclua um botão de comando neste formulário com o Name igual  btnExecutar e Text igual a Executar conforme mostra a figura abaixo:

Antes de podermos usar o evento Click do botão vamos criar os métodos Assíncronos no projeto Class Library: Net_ProgAsync.CLDemo

Projeto Class Library : Criando métodos Assíncronos

Abra o arquivo Exemplo.cs do projeto Class Library e vamos criar os seguintes métodos na classe Exemplo:

1- Método Task_TResult_Async() que possui um retorno do tipo Task<TResult>, que no exemplo é um Boolean.

 Este método apenas verifica se um determinado ano é bissexto retornando true em caso positivo:

        async Task<bool> Task_TResult_Async()
        {
            return await Task.FromResult<bool>(DateTime.IsLeapYear(DateTime.Now.Year));
        }

2- Método Task_Void_Async que retorna void. O método retorna um Task para permitir usar o operador await.

    O método não retorna nenhum resultado, por isso é um método que retorna void. Porém para poder usar o operador await retornamos um tipo Task:

          async Task Task_Void_Async()
        {
            await Task.Delay(5000);
            Console.WriteLine("5 segundos de atraso");
        }

 

3- Método Task_LongaDuracao que vai chamar os métodos anteriores e exibirá o resultado da verficação do ano bissexto. Note que estamos usando a palavra await na chamada dos dois métodos:

O operador await é aplicado a uma tarefa em um método assíncrono para inserir um ponto de suspensão na execução do método até que a tarefa aguardada seja concluída. A tarefa representa um trabalho em andamento.

        public async Task Task_LongaDuracao()
        {
            bool isAnoBissexto = await Task_TResult_Async();
            Console.WriteLine($"{DateTime.Now.Year} {(isAnoBissexto ? " é " : " não é ")} um Ano Bissexto");
            await Task_Void_Async();
        }

 

Agora podemos retornar ao projeto Windows Forms e incluir o código abaixo no evento Click do botão de comando Executar:

using Net_ProgAsync.CLDemo;
using System;
using System.Windows.Forms;
namespace Net_ProgAsync.WF
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private async void btnExecutar_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Evento do botão foi iniciado : cliquei aqui");
            Exemplo oProgAsync = new Exemplo();
         await oProgAsync.Task_LongaDuracao();
            Console.WriteLine("Evento do botão foi concluído");
        }
    }
}

Neste código a primeira coisa que fizemos foi incluir a palavra async no evento pois estamos usando a palavra await na chamada do método Task_LongaDuracao() da classe Exemplo(), cuja instância criamos no código do botão.

A palavra await só pode ser usada em um método assíncrono modificado pela palavra-chave async. Esse tipo de método, definido pelo uso do modificador async e, geralmente, contendo uma ou mais expressões await, é conhecido como um método assíncrono.

Executando o projeto Windows Forms e verificando o resultado

Vamos executar a solução que irá apresentar o formulário Form1.cs. Antes de clicar no botão de comando torne a janela Output (Ctrl+ Alt + O) visível conforme abaixo:

Ao clicar no botão de comando você verá a exibição do resultado na janela Output e vai notar que o formulário executa a operação e continua responsivo.

Para deixar bem claro que estamos executando operações assíncronas vamos alterar o código do método Task_LongaDuracao conforme abaixo:

        public async Task Task_LongaDuracao()
        {
            bool isAnoBissexto = await Task_TResult_Async();
            for (int i = 0; i <= 10000; i++)
            {
                i++;
            }
            isAnoBissexto = await Task_TResult_Async();
            Console.WriteLine($"{DateTime.Now.Year} {(isAnoBissexto ? " é " : " não é ")} um Ano Bissexto");
            await Task_Void_Async();
            Task taskTResultAsync = Task_TResult_Async();
            for (int i = 0; i <= 10000; i++)
            {
                i++;
            }
            await taskTResultAsync;
        }

Agora estamos incluindo uma demora maior na execução das tarefas do método para você notar que o formulário Windows Forms fica liberado executando em uma thread separada enquanto a execução do método Task_LongaDuracao  realiza as tarefas designadas.

Pegue o projeto aqui : Net_ProgAsync.zip

"Mas nós não recebemos o espírito do mundo, mas o Espírito que provém de Deus, para que pudéssemos conhecer o que nos é dado gratuitamente por Deus. "
1 Coríntios 2:12

Referências:


José Carlos Macoratti