ASP .NET Core - Posso eliminar o uso do async/await ?


 Hoje vamos discutir sobre a possibilidade de eliminar o uso do async/await na ASP .NET Core.

Você já deve saber que o uso da programação assíncrona (leia-se async/await) na plataforma .NET não tem como objetivo aumentar o desempenho, mas esta relacionada em aumentar a quantidade de requests que podem ser tratados ao mesmo tempo usando os mesmos recursos.

Desta forma a programação assíncrona faz apenas uma coisa : Se uma tarefa está sendo aguardada e essa tarefa não envolve trabalho vinculado à CPU e, como resultado, a thread fica ociosa, então, essa thread pode ser liberada para retornar ao pool de threads para fazer outro trabalho.

Quando você usa async/await em seu código para tratar com a programação assíncrona o objetivo é usar os recursos com mais eficiência, e isso esta relacionada com operações de I/O (input/output) e não operações vinculadas a CPU.

Isso nos leva a pensar da seguinte forma :

Então não devemos usar async e await ???

Não é esta a conclusão que você deve chegar.

Se hoje você considerar que o uso da programação assíncrona não vai lhe trazer os benefícios esperados quem garante que no futuro isso não vai mudar ?

Agora imagine você ter que refatorar o seu código adequando-o à programação assíncrona no futuro !!!

O custo de desempenho da programação assíncrona geralmente é insignificante e, se você precisar dela, isso salvará a sua aplicação.

Posso eliminar o uso de async/await

Outro ponto de discussão que ainda existe é a possibilidade de eliminar o uso do async/await em certos cenários devido ao custo envolvido com sua utilização.

Considere o seguinte exemplo:

public  async Task ExemploAsync(int id)
{      
      return await MetodoExemploAsync();
}

Aqui temos o trio dinâmico em ação : async, await e Task

Estamos retornando um Task que é aguardada (waited) e desembrulhada, e a seguir uma nova Task é criada para retornar de MetodoExemploAsync()

Como isso tem um custo que tal se escrevermos o código eliminando o async e o await:

public  Task ExemploAsync(int id)
{      
      return  MetodoExemploAsync();
}

Agora o Task retornado por MetodoExemploAsync é retornado diretamente por ExemploAsync e isso pode reduzir o overhead do uso de async/await.

A argumentação a favor desta abordagem pode afirmar que :

"É mais eficiente eliminar o async e await, pois ao não incluir essas palavras-chave, o compilador pode pular a geração da máquina de estado assíncrona. Isso significa que há menos tipos gerados pelo compilador em seu assembly, menos pressão no coletor de lixo e menos instruções da CPU para executar."

Acontece que cada um desses ganhos é absolutamente mínimo. Há um tipo a menos, um punhado de pequenos objetos salvos do GC(Garbage Collector) e apenas algumas instruções da CPU ignoradas. Na grande maioria das vezes, o uso do assíncrono está lidando com E/S, o que diminui completamente qualquer ganho de desempenho.

Assim na maioria dos cenários, eliminar o uso de async/await  não faz nenhuma diferença no tempo de execução de seu aplicativo, e mesmo que a não utilização de async e await possa evitar as modificações do compilador em seu método,  isso também significa que todas as modificações do compilador em seu método agora devem ser feitas manualmente se você deseja a mesma semântica.

Outra problema em eliminar o async/await é o tratamento de exceções. A máquina de estado para métodos assíncronos irá capturar exceções de seu código e colocá-las na Task retornada. Sem o uso da palavra-chave async, a exceção será gerada diretamente, em vez de prosseguir na tarefa.

Assim a recomendação é continuar usando async/await mesmo que no momento você tenha certeza de que isso não vai te trazer os benefícios esperados.

E estamos conversados...

"(Disse Jesus) Eu sou a videira verdadeira, e meu Pai é o agricultor.
Todo ramo que, estando em mim, não der fruto, ele o corta; e todo o que dá fruto limpa, para que produza mais fruto ainda."

João 15:1,2

Referências:


José Carlos Macoratti