C# - Sete formas de iniciar uma Task (Tarefa)


  Neste artigo vou mostrar 7 maneiras diferentes que podemos usar para iniciar uma tarefa ou task usando a linguagem C#.

A partir da versão  4.0 da plataforma .NET versão temos disponível o namespace System.Threading.Tasks, o qual contém classes que permitem abstrair a funcionalidade de threading onde, na verdade, por trás dos panos, uma ThreadPool é usada.

Uma tarefa (ou task) representa uma unidade de trabalho que deverá ser realizada. Esta unidade de trabalho pode rodar em uma thread separada e é também possível iniciar uma task de forma sincronizada a qual resulta em uma espera pela thread chamada. Com Tasks, você tem uma camada de abstração mas também um bom controle sobre as threads relacionadas.

As tarefas (tasks) permitem muito mais flexibilidade na organização do trabalho que você precisa fazer. Por exemplo, você pode definir continuar o trabalho, que deve ser feito depois que uma tarefa esteja completa.

Isso pode diferenciar se um tarefa foi executada com sucesso ou não. Você também pode organizar as tarefas em uma hierarquia onde uma tarefa pai pode criar novas tarefas filhas que podem criar dependências e assim o cancelamento da tarefa pai também cancela suas tarefas filhas.

Para iniciar uma tarefa, você pode usar a classe TaskFactory ou o construtor da classe Task e o método Start().

O construtor Task lhe dá mais flexibilidade na criação da tarefa. Ao iniciar uma tarefa, uma instância da classe Task pode ser criada e o código que deve ser executado pode ser atribuído com uma Action ou delegate Action<object> tanto sem parâmetro como com um parâmetro object. Isto é semelhante ao que você viu na classe Thread.

Vou mostrar a seguir como podemos iniciar uma Task de 7 formas diferentes.

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando o projeto no VS Community

Abra o VS Community e clique em New Project;

Selecione a linguagem Visual Basic e o template Console Application;

Informe o nome da solução como Tarefas clique no botão OK;

- Declarando os namespaces no projeto

using System;
using System.Threading.Tasks;

- Criando os métodos ExibirMensagem() e Somar()

        //----------------métodos ExibirMensagem() e Somar --------------
        private static void ExibirMensagem()
        {
            Console.WriteLine("Macoratti .net - Iniciando Task !");
        }

        private static int Somar(int a, int b)
        {
            return a + b;
        }

Vamos criar esses dois métodos dentro da classe Program que serão usados no exemplos.

1 - Iniciando Task da forma mais direta possível

O método (Action) Task.Factory.StartNew() cria e inicia uma task, sendo equivalente a criar uma tarefa usando um dos construtores da classe Task() e a seguir chamar o método Task.Start() para agendar a tarefa para execução:

        private static void primeiraTask()
        {
            Task.Factory.StartNew(() => { Console.WriteLine("Macoratti .net - Iniciando Task !"); });
        }

2 - Iniciando Task usando uma Action

O Delegate Action encapsula um método que não retorna nenhum valor (void) e pode receber de zero a 16 parâmetros de entrada.

        private static void segundaTask() 
        {
            Task task = new Task(new Action(ExibirMensagem));
            task.Start();
        }

3 - Iniciando Task usando um delegate

Um Delegate é um ponteiro para um método e pode ser passado como um parâmetro para um método.

Podemos mudar a implementação do método dinamicamente em tempo de execução, a única coisa que precisamos fazer para conseguir isso seria manter o tipo de parâmetro e o tipo de retorno.

        private static void terceiraTask()
        {
            Task task = new Task(delegate { ExibirMensagem(); });
            task.Start();
        }

4 - Iniciando Task usando expressão lambda e método nomeado

As expressões lambdas são funções que podem conter expressões e declarações que são usadas para criar delegates e árvores de expressões onde o tipo das variáveis não precisam ser declarados visto que elas usam métodos anônimos.

     private static void quartaTask()
        {
            Task task = new Task(() => ExibirMensagem());
            task.Start();
        }

5 - Iniciando Task usando expressão lambda e método anônimo

Os tipos anônimos fornecem uma maneira conveniente para encapsular um conjunto de propriedades somente leitura em um único objeto sem precisar primeiro definir explicitamente um tipo.

O nome do tipo é gerado pelo compilador e não está disponível no nível do código fonte. O tipo das propriedades é inferido pelo compilador.

     private static void quintaTask()
        {
            Task task = new Task(() => { ExibirMensagem(); });
            task.Start();
        }

6 - Iniciando Task usando o método Task.Run (.NET 4.5)

O método Task.Run() enfileira a tarefa especificada em um pool de threads e retorna o objeto Task que representa a tarefa.

O método Run permite criar e executar uma tarefa em uma única chamada de método e é uma alternativa mais simples ao método StartNew. Ele cria uma tarefa com os seguintes valores padrão:

- Seu token Cancelation é igual a CancellationToken.None;
- O valor da sua propriedade CreationOptions é TaskCreationOptions.DenyChildAttach;
- Usa o agendador de tarefas padrão.

        private async Task sextaTask()
        {
            await Task.Run(() => ExibirMensagem());
        }

7 - Iniciando Task usando o método Task.FromResult para retornar um resultado da Task (.NET 4.5)

O método FromResult cria uma Task<TResult> que é completada com sucesso com o resultado especificado.

       public  async Task setimaTask()
        {
            int res = await Task.FromResult<int>(Somar(4, 5));
        }

Este método cria um objeto Task<TResult> cuja propriedade Task<TResult>.Result é o resultado e cuja propriedade Status é TaskStatus.RanToCompletion.

O método é usado quando o valor de retorno de uma tarefa é imediatamente conhecido, sem a execução de um caminho de código mais longo.

Pegue o projeto completo aqui : Tarefas.zip

Porque a palavra de Deus é viva e eficaz, e mais penetrante do que espada alguma de dois gumes, e penetra até à divisão da alma e do espírito, e das juntas e medulas, e é apta para discernir os pensamentos e intenções do coração.
Hebreus 4:12

Referências:


José Carlos Macoratti