Article image
Lucas Soares
Lucas Soares23/02/2024 10:49
Compartilhe

Como usar o Task.Run() em C#

    Como usar o Task.Run() em C#

    A execução de tarefas em paralelo é uma operação essencial na programação. Neste artigo, pretendo explorar como podemos usar o "Task.Run()" ao nosso favor.

    Como Funciona a programação Síncrona e Assíncrona

    A programação pode ser classificada como programação síncrona ou assíncrona dependendo de como as tarefas são executadas.

    Síncrono ou Assíncrono é quando um fluxo de tarefa é ou não executado junto a outra tarefa. Por exemplo no preparo de uma comida você pode fazer o arroz enquanto o feijão esta cozinhando, isso pode ser considerado um fluxo de tarefa assíncrona.

    Síncrono: É quando uma tarefa é executada uma atrás da outra, ou seja , uma tarefa precisa ser concluída para que a próxima tarefa possa começar. É como fazer uma receita de bolo onde tem que seguir o passo a passo ate concluir a receita.

    Assíncrono: É quando as tarefas podem ser executas simultaneamente. Enquanto uma tarefa esta sendo executada, outra tarefa também esta sendo executada junto. Como no exemplo acima de fazer arroz e feijão ao mesmo tempo.

    image

    Uso básico do Task.Run()

    Para usá-lo, basta chamar a função Task.Run().

    Console.WriteLine("Primeiro WriteLine: Executando uma tarefa síncrona.\n");
    
    
    Task.Run(() =>
    {
      Console.WriteLine("Segundo WriteLine: Executando uma tarefa Assíncrona.");
    });
    
    
    Console.WriteLine("Terceiro WriteLine: Executando uma tarefa síncrona.\n");
    Console.WriteLine("Quarto WriteLine: Executando uma tarefa síncrona.\n");
    

    Onde a saída seria.

    Primeiro WriteLine: Executando uma tarefa síncrona.
    
    
    Terceiro WriteLine: Executando uma tarefa síncrona.
    
    
    Quarto WriteLine: Executando uma tarefa síncrona.
    
    
    Segundo WriteLine: Executando uma tarefa Assíncrona.
    

    E caso você deseje que quando a tarefa assíncrona quando terminar retornar uma valor também podemos retornar um valor de uma tarefa, usando o `Task.Run<TResult>()`.

    var task = Task.Run(() =>
    {
     return "Resultado da tarefa";
    });
    
    Console.WriteLine(task.Result);
    

    Onde a saída seria.

    Resultado da tarefa
    

    Usando o Task.Run() com uma função assíncrona.

    Para executar uma função assíncrona, é um pouco mais elaborado, mas também não tão complexo. É necessário informar ao método 'Task.Run()' a função assíncrona a ser executada.

    async Task<string> FuncaoAssincrona()
    {
     await Task.Delay(1000);
     return "Resultado após 1 segundo";
    }
    
    var task = Task.Run(() => FuncaoAssincrona());
    
    Console.WriteLine(task.Result);
    

    Onde a saída seria.

    Resultado após 1 segundo
    

    Explorando o Task.Run()

    O método 'Task.Run()' oferece uma notável flexibilidade ao possibilitar as execuções múltiplas de tarefas simples, mas também de tarefas complexas ou aquelas que requerem cálculo prévio antes da execução, por exemplo.

    var task = Task.Run(() =>
    {
     var soma = 0;
     for (var i = 0; i < 100; i++)
     {
    soma += i;
     }
     return soma;
    });
    Console.WriteLine(task.Result);
    

    Onde a saída seria.

    4950
    

    Para mais exemplos de como usar o Task.Run() pode se encontrar na documentação do site da Microsoft Docs

    https://docs.microsoft.com/pt-br/dotnet/api/system.threading.tasks.task.run?view=net-6.0

    Caso de Uso

    Vamos considerar que estejamos fazendo um programa que tem que fazer 3 requisições para seu programe funcionar. Dependendo do que essa API retorne, pode demorar um tempo para que ela retorne, e se considerar que as outras API também pode demorar algum tempo. Isso faz com que seu programa demore para responder, oque pode ser algo bem danoso. Nesse caso se o seu programe for assíncrono isso pode resolver em grande parte a demora que as API demora para responder.

    using System;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    class Program
    {
    static async Task Main(string[] args)
    {
      await ProcessarRequisicoesDeRedeAsync();
    }
    
    static async Task ProcessarRequisicoesDeRedeAsync()
    {
      var httpClient = new HttpClient();
      var urls = new string[] { "https://api.postmon.com.br/v1/cep/32010330", "https://api.postmon.com.br/v1/cep/29175439", "https://api.postmon.com.br/v1/cep/29175625" };
    
      var tasks = new Task<string>[urls.Length];
    
      for (int i = 0; i < urls.Length; i++)
      {
        
        var index = i;
        tasks[index] = Task.Run(async () =>
        {
          var response = await httpClient.GetAsync(urls[index]);
          return await response.Content.ReadAsStringAsync();
        });
      }
    
      await Task.WhenAll(tasks);
    
      foreach (var task in tasks)
      {
        Console.WriteLine($"Resposta da API: {task.Result}");
        Console.WriteLine("\n -----------------------------\n");
      }
    }
    }
    

    Onde a saída seria.

    Resposta da API: {"bairro": "Bela Vista", "cidade": "Contagem", "logradouro": "Avenida Jos\u00e9 Diniz e Silva", "estado_info": {"area_km2": "586.521,235", "codigo_ibge": "31", "nome": "Minas Gerais"}, "cep": "32010330", "cidade_info": {"area_km2": "195,045", "codigo_ibge": "3118601"}, "estado": "MG"}
    
     -----------------------------
    
    Resposta da API: {"bairro": "Residencial Jacara\u00edpe", "cidade": "Serra", "logradouro": "Rua Castelo Branco", "estado_info": {"area_km2": "46.089,390", "codigo_ibge": "32", "nome": "Esp\u00edrito Santo"}, "cep": "29175439", "cidade_info": {"area_km2": "547,637", "codigo_ibge": "3205002"}, "estado": "ES"}
    
     -----------------------------
    
    Resposta da API: {"bairro": "das Laranjeiras", "cidade": "Serra", "logradouro": "Travessa Santa L\u00facia", "estado_info": {"area_km2": "46.089,390", "codigo_ibge": "32", "nome": "Esp\u00edrito Santo"}, "cep": "29175625", "cidade_info": {"area_km2": "547,637", "codigo_ibge": "3205002"}, "estado": "ES"}
    
     -----------------------------
    

    Como funciona o Task.Run() por baixo dos panos

    A ideia por trás do Task.Run() é explorar a capacidade de execução paralela e assíncrona dos processadores modernos para melhorar o desempenho do programa. Ele faz isso dividindo a tarefa em sub-tarefas que podem ser executadas em paralelo.

    O Task.Run() opera em cinco passos, sendo eles

    1 - Execução da Tarefa: O Task.Run() inicia a execução da tarefa em segundo plano. A tarefa é executada em uma thread separada que é gerenciada pela ThreadPoll.

    2 - Aguardando a Conclusão: O método retorna uma instância que pode ser usadapara acompanhar a conclusão da tarefa. Onde pode ser usado o metodo Wait(), WaitAll(), WaitAny ou await para aguardar a tarefa termina.

    3 - Manipulação de Exceções: Se a tarefa lançar uma exceção, ela será armazenada e relançada quando você chama Wait(), Result ou quando você tenta acessa o resultado da tarefa.

    4 - Retorno: Se a tarefa retorna um valor, o resultado é armazenado na tarefa e pode ser recuperado através da propriedade Result da tarefa.

    5 - Continuações: Você pode anexar "Continuações " à tarefa que acabou de ser concluída e deve fazer alguma ação depois disso.

    Vantagens

    Melhora a Responsividade da Aplicação: Ao utilizar o Task.Run() permite ser executada em segundo plano, evitando bloqueios na thread principal. Resultando em aplicações mais responsiva. Além de melhor aproveitamento de recurso de processamento.

    Desvantagem

    Possível Sobrecarga de Threads: O uso excessivo de operações assíncronas pode levar á criação de novos threads desnecessariamente, o que pode resultar em sobrecarga do sistema e consumo excessivo de recurso.

    Complexidade na Depuração: Quando vários operações assíncronas são iniciadas, pode ficar mais difícil rastrear o fluxo de execução e depurar problemas de concorrência.

    Conclusão

    Através do método Task.Run(), é viável executar uma variedade de tarefas com diferentes tipos de complexidade. Dominar o uso do Task.Run() é uma habilidade fundamental para qualquer desenvolvedor que lide com a execução de tarefas múltiplas em seus projetos.

    Documentação

    Microsoft Docs: https://docs.microsoft.com/pt-br/dotnet/api/system.threading.tasks.task.run?view=net-6.0

    Compartilhe
    Comentários (0)