C# - Programação Assíncrona - I
Vamos recordar conceitos importantes da programação assíncrona na linguagem C# |
Neste artigo, vamos recordar os conceitos da programação assíncrona com exemplos de código, ou seja, o que é programação assíncrona, como ela é diferente da programação síncrona, como implementá-la no .NET Core usando async & await, quando e onde ela deve ser usada junto com onde é melhor evitar o seu uso.
Nos dias de hoje,
considerando a natureza dos aplicativos, sua carga e a demanda constante dos
clientes para melhorar a escalabilidade do aplicativo, torna-se muito importante
entender e implementar adequadamente os conceitos de programação assíncrona em
seu aplicativo.
Se você tiver alguma necessidade de realizar operações de I/O (como solicitar
dados de uma rede, acessar um banco de dados ou ler e gravar em um sistema de
arquivos), você desejará utilizar a programação assíncrona. Você também pode
ter código vinculado à CPU, como executar um cálculo complexo e demorado, que
também é um bom cenário para escrever código assíncrono.
O C# possui um modelo de programação assíncrona em nível de linguagem, que
permite escrever facilmente código assíncrono sem ter que fazer malabarismos com
retornos de chamada ou estar em conformidade com uma biblioteca que oferece
suporte à assincronia. Ela segue o que é conhecido como
Padrão Assíncrono Baseado em Tarefas (TAP).
Como muitas outras linguagens de programação, o C# também oferece suporte à programação assíncrona e quando se trata de programação assíncrona no .NET, existem 2 palavras-chave muito importantes : async e await.
O núcleo da programação assíncrona no .NET são os objetos Task e Task<T>, que modelam operações assíncronas. Eles são suportados pelas palavras-chave async e await.
A palavra-chave await é onde a mágica acontece. Ela cede o controle ao chamador do método que executou o await e, em última análise, permite que uma interface do usuário seja responsiva ou um serviço seja elástico. Embora existam maneiras de abordar o código assíncrono diferente de async e await, vamos focar neste recurso.
Os códigos mostrados neste artigo, foram criados usando o C# 11 e o Visual Studio Community 2022 (17.5.1) no ambiente do .NET 7.0.
Programação Assíncrona x Programação Paralela
A programação
assíncrona e a programação paralela são duas técnicas diferentes para melhorar o
desempenho de aplicativos e aproveitar melhor os recursos do sistema. No C#,
ambas as técnicas são suportadas nativamente e oferecem recursos poderosos para
lidar com tarefas que exigem muito processamento.
A programação assíncrona é um modelo de programação
que permite que o aplicativo execute várias tarefas ao mesmo tempo sem
bloquear a thread principal. Isso é feito usando a palavra-chave "async"
e a biblioteca de tarefas TPL (Task Parallel Library)
do .NET. Com a programação assíncrona, o aplicativo pode continuar executando
outras tarefas enquanto aguarda a conclusão de uma operação de I/O ou de um
cálculo complexo em outra thread. Isso pode melhorar significativamente a
capacidade de resposta do aplicativo e a utilização do processador.
A programação paralela, por outro lado, é um modelo
de programação que permite que o aplicativo execute várias tarefas ao mesmo
tempo, aproveitando os recursos do processador. Isso é feito usando a biblioteca
Parallel do .NET, que fornece vários métodos para
executar operações em paralelo. Com a programação paralela, o aplicativo pode
dividir uma tarefa em várias partes menores e executá-las simultaneamente em
várias threads ou núcleos de processador. Isso pode acelerar a execução da
tarefa e reduzir o tempo de resposta do aplicativo.
Programação Assíncrona x Programação Síncrona
Já na programação assíncrona, as tarefas são executadas em paralelo, sem bloquear a execução do programa. Isso significa que, em vez de aguardar a conclusão de uma tarefa antes de iniciar a próxima, é possível iniciar várias tarefas ao mesmo tempo e esperar pela conclusão de cada uma delas.
No C#, o suporte à programação assíncrona foi adicionado na versão 5.0 da linguagem. Uma das principais formas de se trabalhar com programação assíncrona em C# é por meio do uso de palavras-chave como "async" e "await".
Ao se utilizar essas palavras-chave, é possível criar métodos que executam tarefas assincronamente, ou seja, sem bloquear a execução do programa. Quando um método é marcado como "async", ele pode ser interrompido durante a sua execução, permitindo que outras tarefas sejam executadas em paralelo.
O uso da programação assíncrona é indicado para situações em que a execução de uma tarefa pode levar muito tempo ou quando há a necessidade de se realizar várias tarefas simultaneamente. Por outro lado, a programação síncrona é mais indicada para situações em que a execução das tarefas deve ser feita de forma sequencial, uma após a outra, ou quando não há a necessidade de se realizar tarefas simultaneamente
Programação Assíncrona
A programação
Assíncrona permite que você execute a tarefa em segundo plano, de forma que o
processo ou thread não esteja ocupado ou bloqueado. Ela também permite executar
duas ou mais tarefas independentes em paralelo. Este modo non-blocking e
paralelização permitem evitar ou reduzir os atrasos devido a esperas/bloqueios
que ocorrem durante a execução do código.
Nem todas as tarefas podem ser executadas em paralelo, pois algumas tarefas
podem depender do resultado de outra tarefa, ou seja, pode haver um cenário como
esse, precisamos executar a tarefa 2 somente se a tarefa 1 for bem-sucedida,
nesse caso, teremos que aguardar a tarefa 1 para concluir e, em seguida, com
base no resultado da tarefa 1, precisamos decidir se podemos executar a tarefa 2
ou não.
A programação assíncrona é usada não apenas para melhorar o desempenho ou a
escalabilidade de seu aplicativo, mas também para melhorar a experiência geral
do usuário com o aplicativo.
No C#, usamos as palavras-chave async e await
para implementar a programação assíncrona. Para qualquer método ser assíncrono,
temos que adicionar a palavra-chave async na
definição do método antes do tipo de retorno do método. Além disso, é prática
geral adicionar Async ao nome do método se esse
método for assíncrono.
public
async
Task SaveDataAsync() { //Salvar Dados } |
Tipos de retorno na programação assíncrona
Os tipos de retorno assíncronos ou Async Return Types são os tipos de retorno assíncronos disponíveis no C# para representar o resultado de uma operação assíncrona. Eles permitem que uma operação assíncrona possa retornar um valor e, ao mesmo tempo, ser executada de forma não sequencial e não bloqueante.
Existem os seguintes tipos de retorno assíncronos no C#:
public
async
Task SaveDataAsync() { //Salvar Dados } |
public
async
Task<int> SaveDataAsync() { //Salvar Dados return 1; } |
public
async
ValueTask<int> SaveDataAsync() { //Salvar Dados return 1; } |
public
async
void SaveDataAsync() { //Salvar Dados } |
A classe IAsyncEnumerable<T> é uma interface genérica que define métodos para permitir a iteração assíncrona de uma sequência de valores. Ela é implementada por classes como AsyncEnumerable e AsyncStream, que podem ser usadas para criar e retornar sequências de resultados assíncronos.
A escolha do tipo de retorno adequado depende do tipo de operação assíncrona que está sendo executada. Se a operação não precisar retornar um valor, o tipo Task é suficiente. Se a operação precisar retornar um valor, o tipo Task<T> é o mais apropriado. Já a classe ValueTask<T> é uma opção interessante quando há um grande número de chamadas assíncronas sendo realizadas e a alocação de objetos se torna um problema.
Vantagens, desvantagens e quando usar a programação assíncrona
A seguir temos os
principais benefícios da programação assíncrona:
Maior responsividade
– Ao executar tarefas de longa duração em segundo plano, podemos manter a
interface do usuário no modo sem bloqueio para que os usuários possam interagir
com os aplicativos e realizar outras operações.
Melhoria de desempenho – Podemos melhorar o
desempenho de nosso aplicativo executando tarefas independentes em paralelo e,
se duas ou mais tarefas forem executadas em paralelo, levará menos tempo para a
execução da atividade.
Melhor desempenho: A programação assíncrona permite
que o código execute várias tarefas em paralelo, aproveitando ao máximo os
recursos do sistema. Isso pode resultar em um desempenho significativamente
melhor do que a programação sequencial.
Melhor Escalabilidade: A programação assíncrona
permite que um sistema seja escalonado para suportar mais usuários e operações,
sem a necessidade de adicionar mais recursos de hardware. Isso é particularmente
importante em sistemas que lidam com grande quantidade de solicitações
simultâneas.
Embora
haja benefícios claros da programação assíncrona, ela aumenta a complexidade
durante o desenvolvimento de aplicativos e isso torna os aplicativos assíncronos
muito mais complexos, tornando difícil aprimorar ou modificar a funcionalidade
do aplicativo. Também é difícil depurar e encontrar bugs em aplicativos
assíncronos. Como há várias tarefas em execução em paralelo, aumenta o número de
objetos na memória e também, em alguns casos, esses objetos precisam ficar mais
tempo na memória até que todas as tarefas sejam concluídas.
A programação assíncrona pode ser usada para a tarefa de bloqueio de execução
longa. Sempre que houver um código de bloqueio que pode ser executado
independentemente do restante do processo, nesse caso, podemos executar esse
código como uma tarefa assíncrona. Esse modo de tarefa assíncrona executará esse
trecho de código em uma thread diferente em vez da thread principal e a thread
principal pode ficar livre para manter o aplicativo no estado de resposta.
Exemplos de tarefas de longa execução na programação podem ser: ler
ou gravar um arquivo, chamadas HTTP para uma API externa de terceiros, fazer
chamadas de banco de dados pela rede, realizar cálculos pesados nos dados,
gravar logs de aplicativos em um arquivo, etc.
O que acontece debaixo das cobertas
No lado C# das coisas, o compilador transforma seu código em uma máquina de
estado que monitora coisas como ceder a execução quando uma espera é alcançada e
retomar a execução quando uma tarefa em segundo plano é concluída.
Pontos chaves a compreender :
Após toda essa teoria, indigeta mas necessária, vamos arregaçar as mangas e por tudo isso em prática mostrando agora exemplos de uso da programação assíncrona na linguagem C#.
Na próxima parte do artigo vamos iniciar a parte prática.
E estamos conversados...
"Todas as coisas são puras para os puros, mas nada
é puro para os contaminados e infiéis; antes o seu entendimento e consciência
estão contaminados."
Tito
1:15
Referências:
NET - Unit of Work - Padrão Unidade de ...
http://msdn.microsoft.com/en-us/library/vstudio/hh156513.aspx